1、浏览器的限制:当浏览器发现你的请求是跨域的时候,会做校验,如果校验不通过,将会报跨域安全问题。浏览器多管闲事, get请求能正常返回,但是浏览器会报错;说明后台是没问题的,只是浏览器的限制问题。
2、跨域:发出去的请求只要域名,端口,协议中有一个不同,都会产生跨域。
3、发送的是xhr(XMLHTTPRequest)请求,如果发送的不是xhr请求,就算是跨域,浏览器也不会报错。
4、同时满足这三个条件才会报跨域错误。 1、让浏览器不做限制,指定参数,让浏览器不做校验,但该方法不太合理,它需要每个人都去做改动(客户端做改动,不现实)。
2、不要发出XHR请求,这样就算是跨域,浏览器也不会报错,解决方案是JSONP,通过动态创建一个script,通过script发出请求。但JSONP有一些弊端,导致有时候不会使用它。
3、在跨域的角度:一种是被调用方修改代码,加上字段,告诉浏览器,支持跨域,支持调用方调用。第二种是调用方使用代理,在a域名里面的的请求地址使用代理指定到b域名。第一种是支持跨域,第二种是隐藏跨域。
解决方案:
1、浏览器限制(基于同源策略的安全检查)
取消安全检查
打开命令行
输入:chrome --disable-web-security --user-data-dir=g:\temp3
2、JSONP ==> JSONP - 跨域篇
3、解决跨域问题
(1)被调用方解决跨域问题,被调用方修改代码解决。被调用方解决,是基于支持跨域的解决思路,基于http协议关于跨域方面的一些规定,在响应头里加允许调用字段,跨域请求是直接从浏览器发送过去的。
(2)调用方解决跨域,调用方修改Apache或者Nginx静态服务器,通过静态服务器隐藏调用请求返回给前台,前台以为是同一个地址和端口的请求就解决了跨域问题。调用方解决是基于隐藏跨域的解决思路,跨域请求不会直接从浏览器发到被调用方,而是从中间的http服务器转发过去的。 举例子: 调用方为a.com,被调用方为b.com。 被调用方解决时,在浏览器上会看到b.com的url,修改的是被调用方的http服务器。 调用方解决时,在浏览器上看到的都是a.com的url,但是该到b.com的请求还是会到b.com的。修改的是调用方的http服务器。
具体实现:
一、被调用方解决跨域问题
两种方案:
1、在应用服务器(eg:tomcat)中增加响应头。
2、在HTTP服务器(eg:nginx)中增加响应头。
1、在应用服务器(eg:tomcat)中增加响应头——Filter措施
1.1、入门版
(1)添加一个filter(所有请求都经过这个先)
(2)指定可以访问的域名
(3)指定可以访问的方法
Ps:若想允许所有的域名和方法,将上面两处修改为一个星号“*”。
1.2、进阶版
是不是所有请求都先执行后判断?
简单请求先执行后判断,非简单请求会先发送一个预检命令,检查之后才真正发送跨域请求
简单请求与非简单请求如图所示:
当浏览器要发送跨域请求时,如果请求是复杂请求,浏览器会先发送一个options预检命令即一个options请求,当该请求通过时才会再发送真正的请求。
该option请求会根据请求的信息去询问服务端支不支持该请求。比如发送的数据是json类型(通过content-type设置)的话,会携带一个请求头Access-Control-Request-Headers: content-type去询问支不支持该数据类型,如果支持,则请求就会通过,并发送真正的请求。
1.3、优化版
复杂请求每次都要发送两条请求,效率很低,可以通过将预检命令缓存来减少请求。设置方法是服务端响应头设置Access-Control-Max-Age,值是缓存时间(单位秒)。
第一次调用图
第二次调用图
Ps:哪怕在缓存期间,去掉了如下代码,也是能如“第二次调用图”所示。
res.addHeader("Access-Control-Allow-Headers","Content-Type"); res.addHeader("Access-Control-Max-Age", "3600");
1.4、带Cookie的跨域(入门版)
Ps:withCredentials:true携带cookie访问。
带cookie的跨域(发送的cookie只能是被调用方的cookie,而不是调用方的cookie)。
前面设置响应头Access-Control-Allow-Origin: *,可以解决跨域,但是在带cookie的跨域请求中就不能使用了,浏览器会报错。
另外,浏览器还会报另一个错误。
这是只需要在响应头中设置Access-Control-Allow-Credentials的值为true。
总结:带cookie 的时候,origin必须是全匹配,不能试用*;第二就是要增加一个响应头。
1.5、带Cookie的跨域(进阶版)
当产生跨域的时候,请求头中会多一个字段,叫做origin,这个字段有当前域的信息。所以在发送带cookie的请求,后台又不知道调用方的域的信息时,可以先取到请求头中origin字段的值再赋值给响应头的access-control-allow-origin字段中。
这样一来就破解了127.0.0.1不能访问的问题和替代“*”匹配所有的问题。
1.6、带自定义头的跨域
前端
后台业务逻辑
后台过滤器
Ps:注意两个注解的使用,@RequestHeader、@CookieValue。