AJAX跨域完全讲解
今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947
我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候知道了为什么会存在跨域,以及跨域解决的方案有哪些,今天随着课程的学习,又加深了AJAX跨域的理解,以此记录下来。
为什么会发生产生跨域问题?
上面的图也很清晰了,因为浏览器为了安全(同源),本身就限制了。
- 当我们发送XMLHttpRequest请求的时候,如果请求的是别的域(主机域名、端口)不同时,那么就会产生跨域问题(客户端无法获取服务端返回的数据)
值得注意的是:跨域的问题是发生在XMLHttpRequest请求的,也就是说,不是XMLHttpRequest请求是不会有跨域问题的
- 举个很简单的例子:在编写网页的时候,
<img = src = www.xxxx.xxxx/ >
,URL不是本域的还是可以正常获取该图片的
解决跨域问题的思路
明显地,跨域的问题是由于浏览器限制的,是XMLHttpRequest才会发生的,那么我们可以以这个思路去找找解决思路:
对于浏览器的问题,可以使用相关的参数进行启动浏览器,是可以解决跨域的问题,但是通用性是极低的,了解即可。
JSONP解决跨域
JSONP是JSON使用的一种补充方式,不是官方的协议。JSONP是一种解决跨域问题的一种协议
JSONP这种解决方案其实现在已经很少用了(复杂一点,需要修改后台代码),但我们可以适当了解一下。
使用步骤
在后端增加一个控制器,继承AbstractJsonpResponseBodyAdvice类,完整代码如下:
@ControllerAdvice
publicclassJsonpAdviceextendsAbstractJsonpResponseBodyAdvice{
publicJsonpAdvice(){
// TODO Auto-generated constructor stub
super("callback2");
}
}
前端ajax请求:
// 服务器返回的结果
varresult;
$.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是怎么理解的,我就直接摘抄一下:https://segmentfault.com/a/1190000012469713#articleHeader8的了。
在Java中,我们写下面这个过滤器,就可以完全解决跨域的问题了:
packagecom.imooc;
importjava.io.IOException;
importjavax.servlet.Filter;
importjavax.servlet.FilterChain;
importjavax.servlet.FilterConfig;
importjavax.servlet.ServletException;
importjavax.servlet.ServletRequest;
importjavax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.apache.tomcat.util.buf.StringUtils;
publicclassCrosFilterimplementsFilter{
@Override
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
// TODO Auto-generated method stub
}
@Override
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)
throwsIOException,ServletException{
// TODO Auto-generated method stub
HttpServletResponseres=(HttpServletResponse)response;
HttpServletRequestreq=(HttpServletRequest)request;
//带cookie的时候,origin必须是全匹配,不能使用*
Stringorigin=req.getHeader("Origin");
if(!org.springframework.util.StringUtils.isEmpty(origin)){
res.addHeader("Access-Control-Allow-Origin",origin);
}
res.addHeader("Access-Control-Allow-Methods","*");
// 支持所有自定义头和预检命令(非简单请求会有预检命令)
Stringheaders=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
publicvoiddestroy(){
// TODO Auto-generated method stub
}
}