AJAX跨域彻底讲解

AJAX跨域彻底讲解

今天在慕课网上学习了AJAX跨域彻底讲解:www.imooc.com/learn/947html

我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候知道了为何会存在跨域,以及跨域解决的方案有哪些,今天随着课程的学习,又加深了AJAX跨域的理解,以此记录下来。前端

 

 

为何会发生产生跨域问题?

上面的图也很清晰了,由于浏览器为了安全(同源),自己就限制了。java

  • 当咱们发送XMLHttpRequest请求的时候,若是请求的是别的域(主机域名、端口)不一样时,那么就会产生跨域问题(客户端没法获取服务端返回的数据)

值得注意的是:跨域的问题是发生在XMLHttpRequest请求的,也就是说,不是XMLHttpRequest请求是不会有跨域问题的nginx

  • 举个很简单的例子:在编写网页的时候,<img = src = www.xxxx.xxxx/ >,URL不是本域的仍是能够正常获取该图片的

解决跨域问题的思路

明显地,跨域的问题是因为浏览器限制的,是XMLHttpRequest才会发生的,那么咱们能够以这个思路去找找解决思路:面试

 

 

对于浏览器的问题,可使用相关的参数进行启动浏览器,是能够解决跨域的问题,可是通用性是极低的,了解便可。ajax

JSONP解决跨域

JSONP是JSON使用的一种补充方式,不是官方的协议。JSONP是一种解决跨域问题的一种协议spring

JSONP这种解决方案其实如今已经不多用了(复杂一点,须要修改后台代码),但咱们能够适当了解一下。apache

使用步骤

在后端增长一个控制器,继承AbstractJsonpResponseBodyAdvice类,完整代码以下:json

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

	public JsonpAdvice() {
		// TODO Auto-generated constructor stub
		super("callback2");
	}
}

前端ajax请求:segmentfault

// 服务器返回的结果
	var result;

	$.ajax({
		url: base +"/get1",
		dataType: "jsonp",
		jsonp: "callback2",

		//是否须要缓存,若是这里没有配置缓存,那么请求的URL还会有一个参数
		cache:true,
		success: function(json){
			result = json;
		}
	});

注意的是,前端AJAX的jsonp: "callback2",要和咱们的Controllersuper("callback2");是一致的,否则是不会有效的。

JSONP原理是动态建立script来进行请求的:

 

 

JSONP的弊端:

  • 要对服务器的代码进行改动
  • 只支持GET方法(原理是动态建立script来进行请求的)
  • 发送的不是XMLHttpRequest请求(XMLHttpRequest请求有不少好用的特性)

参考资料:

CORS解决跨域问题

CORS解决跨域问题(也就是咱们服务端被调用方解决跨域的思路)

对于CORS是怎么理解的,我就直接摘抄一下:segmentfault.com/a/119000001…的了。

 

 

在Java中,咱们写下面这个过滤器,就能够彻底解决跨域的问题了:

package com.imooc;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.buf.StringUtils;

public class CrosFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub

		HttpServletResponse res = (HttpServletResponse) response;
		
		HttpServletRequest req = (HttpServletRequest) request;
		
		
		//带cookie的时候,origin必须是全匹配,不能使用*
		String origin = req.getHeader("Origin");
		if (!org.springframework.util.StringUtils.isEmpty(origin)) {
			res.addHeader("Access-Control-Allow-Origin", origin);
		}
		res.addHeader("Access-Control-Allow-Methods", "*");
		
		// 支持全部自定义头和预检命令(非简单请求会有预检命令)
		String headers = req.getHeader("Access-Control-Request-Headers");
		if (!org.springframework.util.StringUtils.isEmpty(headers)) {
			res.addHeader("Access-Control-Allow-Headers", headers);			
		}
		
		res.addHeader("Access-Control-Max-Age", "3600");
		// enable cookie
		res.addHeader("Access-Control-Allow-Credentials", "true");
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

}

上面提到了非简单请求,那什么是非简单请求呢,能够看下面的图:

 

 

非简单请求会发出一个预检命令的(固然了,咱们上面的Filter已经解决预检命令的问题了):

 

 

Spring框架解决

若是使用的是Spring框架的话,那就只须要一个注解就可以解决跨域的问题了@CrossOrigin

HTTP服务器层

咱们在的商用开发中,通常请求的过程是这样的:浏览器->HTTP服务器(Nginx,Apache)->应用服务器(Tomcat,Weblogic)

上面编写的Filter、Spring框架都是在应用服务器上解决的,咱们也是能够经过HTTP服务器(Nginx,Apache)来进行解决跨域问题的

 

 

Nginx我用过,Apache我却是还没用过,下面就简单记录了Nginx和Apache是如何配置的:

Nginx配置:

 

Apache配置:

 

 

代理解决跨域问题

在以前的图咱们已经看到了,解决跨域的问题能够在“调用方”中来进行解决。

“调用方”解决跨域的问题是这个思路的:让发送出去的请求代理成是本域的

举个例子:

www.zhongfucheng.top是调用方

www.zhongfucheng.site是被调用方

它俩是不一样域的,但咱们能够在nginx或Apache上进行配置代理:将被调用方www.zhongfucheng.site映射成别的路径

好比,像下面的图,将8080端口的映射成了ajaxServer,当调用方访问ajaxServer路径时,这样的方法在外部看起来就不像是跨域了,像是访问本地(8081端口),但实际访问别的域(8080端口)

 

 

总结

令我感到最简单的是经过Spring的注解就能够解决跨域的问题了,JSONP的方式已是不多用的了,由于存在必定的弊端,但了解一下也无妨,毕竟可能面试的时候会问到。当没有用任何框架的时候,写Filter也不麻烦,也只是配置了一下HTTP头信息而已。若是使用Nginx、Apache时,也能够用代理或者配置HTTP头信息均可以解决。看完以后,有没有以为跨域问题就迎刃而解了。

若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章的同窗,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y

相关文章
相关标签/搜索