什么是跨域
因为浏览器的同源策略导致了跨域,就是浏览器在搞事情。
什么同源策略
浏览器的同源策略,要同源说起。顾名思义,同源就是源头相同,即两个页面的协议、端口和域名都相同,任何一个不满足,都会导致跨域。
下表给出了相对http://www.baibai.com/say/one.html同源检测的示例:
URL | 结果 | 原因 |
---|---|---|
http://www.baibai.com/say/other.html | 成功 | 同一域名,同一文件夹 |
http://www.baibai.com/say/hi/another.html | 成功 | 同一域名,不同文件夹 |
https://www.baibai.com/say/oneByOne.html | 失败 | 不同协议 ( https和http ) |
http://www.baibai.com:81/say/two.html | 失败 | 不同域名 ( news和www ) |
http://news.baibai.com/say/three.html | 失败 | 不同域名 ( news和www ) |
跨域如何解决
场景1:基于前端jquery的跨域
如果是一般的ajax请求:
代码语言:javascript复制 $.ajax({
url:'http://news.baibai.com/say/test/testjsonp',
type :'get',
dataType :'text',
success:function(data){
alert(data);
},
error:function(data){
alert(“error”);
}
});
那么在浏览器中会报错。
如果改用jsonp形式的ajax请求,并且通过get请求的方式传入参数,注意:跨域请求是只能是get请求不能使用post请求。
代码语言:javascript复制 <!DOCTYPEhtml>
<html>
<head>
<metacharset="UTF-8">
<title>Inserttitle here</title>
<scripttype="text/javascript"src="./js/jquery.js"></script>
<scripttype="text/javascript">
$(document).ready(function(){
var newId = 1928273643';
$.ajax({
type :'get',
url:'http://news.baibai.com/say/test/testjsonp',
data : {
newId: newId,
},
cache:false,
jsonp:"callback",
jsonpCallback:"success",
dataType :'jsonp',
success:function(data){
alert(data);
},
error:function(data){
alert('error');
}
});
});
</script>
</head>
<body>
<input id=newId'value='546' name=’new'>
<divid='testdiv'></div>
</body>
</html>
jsonp 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)。
jsonpCallback自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名。
场景2:基于后端Java的跨域
自从HTML5出现之后,极大地方便了日常的开发。其实浏览器并没有拦截请求,而是拦截了服务器端返回的响应。所以如果要支持跨域访问,需要浏览器和后台服务器程序同时支持,如果这两个条件不能同时满足,则还是不能支持跨域访问。
响应头有以下几种:
- Access-Control-Allow-Origin:允许跨域访问的域,可以是一个域的列表,也可以是通配符”*”;
- Access-Control-Allow-Methods:允许使用的请求方法,以逗号隔开;
- Access-Control-Allow-Headers:允许自定义的头部,以逗号隔开,大小写不敏感;
- Access-Control-Expose-Headers:允许脚本访问的返回头,请求成功后,脚本可以在XMLHttpRequest中访问这些头的信息。
- Access-Control-Allow-Credentials:是否允许请求带有验证信息,XMLHttpRequest请求的withCredentials标志设置为true时,认证通过,浏览器才将数据给脚本程序。
请求头有以下几种:
- Origin:表明来源域,要与响应头中的Access-Control-Allow-Origin相匹配才能进行跨域访问;
- Access-Control-Request-Method:将要进行跨域访问的请求方法,要与响应头中的Access-Control-Allow-Methods相匹配才能进行跨域访问;
- Access-Control-Request-Headers:自定义的头部,所有用setRequestHeader方法设置的头部都将会以逗号隔开的形式包含在这个头中,要与响应头中的Access-Control-Allow-Headers相匹配才能进行跨域访问。 如果想要能够跨域进行访问,需要设置如下代码,即在返回头中添加一些字段:
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException,ServletException {
HttpServletRequest req =(HttpServletRequest) request;
HttpServletResponse rep =(HttpServletResponse) response;
// 设置允许请求的域名,即白名单
String allowDomains = {"http://news.baibai.com/say/three.html "};
String originHeads = req.getHeader("Origin");
if(allowOrigins.contains(originHeads)){
rep.setHeader("Access-Control-Allow-Origin",originHeads);
}
}
有时候,在跨域访问的时候会存在访问方式是出了post,get类型的,比如options类型,这种会在有的代码中拦截,无法访问,需要在返回头中加如下字段:
代码语言:javascript复制response.setHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE");
有时候,访问的请求头首部出现其他类型, 那么Access-Control-Allow-Headers 响应首部预检请求,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。如:
代码语言:javascript复制response.setHeader("Access-Control-Allow-Headers","x-requested-with,Origin,Accept");
有时候,会出现前端接口对接的时候,后台一直获取不到值。最后发现request里有值,session也有值,但是session的id却不一致。这就是因为跨域引起的,需要在fitter里加上以下代码:
代码语言:javascript复制response.setHeader("Access-Control-Allow-Credentials","true");
response.setHeader("XDomainRequestAllowed","1");
注意,当在后端Java代码中加入以上代码时,也需要在前端ajax中加入代码:
代码语言:javascript复制var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
再次注意: 服务器端Access-Control-Allow-Credentials = true时,参数Access-Control-Allow-Origin的值不能为 '*'