跨域时怎么处理 cookie?

简介: 跨域时怎么处理 cookie?

前言

一个请求从发出到返回,需要浏览器和服务端的协调配合。浏览器要把自己的请求参数带给服务端,服务端校验参数之后,除了返回数据,也可能会顺便把请求是否缓存,cookie等信息告诉浏览器。当请求是跨域请求的时候,这个过程还要复杂一些。接下来咱们就看看跨域会有什么问题,又需要前后端进行怎样的配合。

普通跨域

我有一个朋友,叫小王。前端小王和后端同事小马准备联调一个登录的api。假设是/login;小王在把登录账号和密码都准备好之后,愉快的发起了post提交。结果很意外,请求的响应被浏览器拦截了,浏览器还贴心的在console上抛出了一个错误。

小王翻译了一下,原来是被CORS策略拦截掉了。这个策略大概意思是说,服务端如果允许不同origin的请求,那就需要在返回的response header里面带上Access-Control-Allow-Origin这个header。否则浏览器在拿到响应并发现响应头里没有这个header时,就会把响应给吞掉,而不会交给js进行下一步处理。


小王把这个事情告诉了小马,然后小马在返回的header中加上了

Access-Control-Allow-Origin: *

现在小王终于可以拿到返回的结果了。

这里要注意,浏览器不是在请求阶段就对请求进行拦截,而是正常发出请求,拿到服务端的响应之后,开始查看响应header里面有没有Access-Control-Allow-Origin这个header,如果没有,响应的结果就不会到js那里去。

非简单请求的跨域

后来小王觉得在post中发送表单格式的body太麻烦,希望使用JSON格式的请求体提交。小马觉得就是几行代码的事,就同意了。但是小王改成JSON的消息体之后发现又被CORS拦截了,并抛出了下面的错误:

在上面的报错中,我们看到了 preflight 的单词。那这又是怎么回事呢?原来,修改请求体之后,这个跨域请求不再是简单请求了,需要在发起请求之前先进行 preflight 请求。那么什么是简单请求呢?


请求方法包括GET, HEAD, POST

response header里面不能包含cors安全header以外的header。

Content-Type 只限于text/plain, multipart/form-data, application/x-www-form-urlencoded

由于json数据的content-type导致这个post请求不再是简单请求,而对于非简单请求,之前允许所有域名跨域访问是被禁止的。所以还是要修改Access

Control-Allow-Origin为特定的请求域名。在开发模式下,可能是-http://localhost:3000之类的。


小马在重新修改Access-Control-Allow-Origin,小王又拿到了登录成功的结果。可以联调下一个api了。

带cookie的跨域

登录是基于session的,也就是说,登录成功后,server会通过set-cookie,将cookie设置到浏览器中,这样,下次访问同源下的api时,cookie就会被带上。

然而,奇怪的是,小王发现登录成功后,调用别的接口,cookie并没有被带上,导致server无法识别出用户信息,最终返回错误(状态码为401)。


withCredentials

原来,浏览器发起跨域请求的时候,是不会主动带上cookie的,如果一个请求需要cookie,需要开发者设置一个选项,以fetch api为例:

fetch('http://baidu.com:3000', {
    // ...
  credentials: 'include'
})

如果使用xhr api来请求,则需要这样写:

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
  if(invocation) {
    invocation.open('GET', url, true);
    invocation.withCredentials = true; // 带上cookie
    invocation.onreadystatechange = handler;
    invocation.send();
  }
}

小王在设置请求之后又发起了一次请求。却发现cookie还是没有带上去。小王只好在MDN继续查看资料,发现在set-cookie时需要带一个sameSite的属性。

sameSite

sameSite是为了防止csrf攻击而产生的属性,如果不知道啥是CSRF攻击,可以自己先去查一下。


由于我们需要在请求中带上cookie,所以需要在set-cookie时将cookie的sameSite设置为none;又由于将sameSite设置为none时,也需要将Secure设置上,所以请求需要基于https;


小王最后一次请求小马对api进行了上诉更改,服务器终于认出请求来自谁,并返回了正确的结果,跨域的踩坑之旅算是告一段落。

总结

很多时候,我们可能只会关注请求体是什么,响应有没有正确返回,而忽略了header部分。殊不知,header在缓存,web安全,浏览器正确解析结果中发挥了重要的作用,比如本文中的一系列Access-Control-Allow-*的header。


为了让web更安全,CORS还在不断地更新,比如这个提案,规定从公网到私网,或者从私网访问local network时,需要设置跨域头,Access-Control-Allow-Private-Network。


相关文章
|
6月前
|
前端开发
解决前端ajax跨域请求不携带cookie信息JSESSIONID的问题
解决前端ajax跨域请求不携带cookie信息JSESSIONID的问题
|
1月前
axios允许跨域cookie
axios允许跨域cookie
32 3
|
Web App开发 前端开发 Java
解决新版chrome跨域问题:cookie丢失以及samesite属性问题
解决新版chrome跨域问题:cookie丢失以及samesite属性问题
1477 0
解决新版chrome跨域问题:cookie丢失以及samesite属性问题
electron升级到20版本后,禁用第三方cookie、跨域问题解决方法
electron升级到20版本后,禁用第三方cookie、跨域问题解决方法
433 0
|
Web App开发 JavaScript 前端开发
【跨域】一篇文章彻底解决跨域设置cookie问题!
之前做项目的时候发现后端传过来的 SetCookie 不能正常在浏览器中使用。是因为谷歌浏览器新版本Chrome 80将Cookie的SameSite属性默认值由None变为Lax。接下来带大家解决该问题。
3233 0
|
JavaScript 前端开发 Java
Vue.js - Axios 访问 Java 后端跨域问题(支持 Cookie)
Vue.js - Axios 访问 Java 后端跨域问题(支持 Cookie)
245 0
Vue.js - Axios 访问 Java 后端跨域问题(支持 Cookie)
|
存储 前端开发 JavaScript
Cors跨域(二):实现跨域Cookie共享的三要素(下)
Cors跨域(二):实现跨域Cookie共享的三要素(下)
Cors跨域(二):实现跨域Cookie共享的三要素(下)
|
存储 安全 JavaScript
Cors跨域(二):实现跨域Cookie共享的三要素(上)
Cors跨域(二):实现跨域Cookie共享的三要素(上)
Cors跨域(二):实现跨域Cookie共享的三要素(上)
|
15天前
|
存储 安全 搜索推荐
理解Session和Cookie:Java Web开发中的用户状态管理
理解Session和Cookie:Java Web开发中的用户状态管理
40 4