前后端分离的项目中,一般前端会有一个域名,后端接口会有一个域名。如果后端接口生成的cookie,前端请求时,cookie无法携带上来
因此前端需要配置withCredentials属性,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials
字段。
前端配置
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie
也无法读取服务器域名下的Cookie。
服务端配置(spring-mvc为例)
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
如果是x-www-form-urlencoded请求时,只会发一个请求,并且会把cookie携带上来,请求如下:
但如果是application/json请求时,则会发送两个请求,第一个为“预检”请求,类型为options。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
而这个“预检”请求中,是不会携带cookie的,因此服务端如果没有做特殊处理,就会去检查“预检”请求中的cookie,如果发现没有,则直接提示未登录,这样就有问题了。
解决方法可以是在检查代码中,遇到OPTIONS请求,先放行,然后再第二次正式的post请求中,则再去对用户鉴权。
if("OPTIONS".equals(request.getMethod())){
return true;
}
下面是“预检”请求和正式请求:
具体的原理可以参考下面的文章,已经说的很清楚了
http://www.ruanyifeng.com/blog/2016/04/cors.html