一个请求从发出到返回,需要浏览器和服务端的协调配合。浏览器要把自己的请求参数带给服务端,服务端校验参数之后,除了返回数据,也可能会顺便把请求是否缓存,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: true
})

如果使用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。希望本文能对您理解跨域有所帮助。(本文完)

参考资料

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies#samesite_cookies

https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication

cookie跨域那些事儿的更多相关文章

  1. 解决cookie跨域访问

    一.前言 随着项目模块越来越多,很多模块现在都是独立部署.模块之间的交流有时可能会通过cookie来完成.比如说门户和应用,分别部署在不同的机器或者web容器中,假如用户登陆之后会在浏览器客户端写入c ...

  2. cookie 跨域访问的解决方案

    Cookie 同域单点登录  最近在做一个单点登录的系统整合项目,之前我们使用控件实现单点登录(以后可以介绍一下).但现在为了满足客户需求,在不使用控件情况下实现单点登录,先来介绍一下单点登录.    ...

  3. asp.net关于Cookie跨域(域名)的问题

    Cookie是一个伟大的发明,它允许Web开发者保留他们的用户的登录状态.但是当你的站点有一个以上的域名时就会出现问题了.在Cookie规范上 说,一个cookie只能用于一个域名,不能够发给其它的域 ...

  4. 基于Cookie跨域的单点登录问题

    由于项目中,需要用的单点登录,主要的思路是:系统1:用户名密码-->写入Cookie-->其他系统读取Cookie. 1.在同一个服务器下的Cookie共享 @Component(&quo ...

  5. golang-在gin中cookie跨域设置(配合ajax)

    1.当我在golang中,在前后端分离的情况下使用cookies时发现,跨域没有被允许.代码如下: func AccessJsMiddleware() gin.HandlerFunc { return ...

  6. nginx处理cookie跨域

    今天在部署公司项目的时候碰到一个问题 项目地址是xxx.xx.xx.122:7480 项目A后台请求地址为xxx.xx.xx.123:8080/data-sso 开始nginx配置是 server { ...

  7. 解决前后端分离后的Cookie跨域问题

    一. 前端Ajax关键配置 $.ajax({ type: "post", url: xxx, data: xxx, contentType: 'application/json', ...

  8. cookie 跨域解决方法

    1.Nginx 正向和反向代理的区别 正向代理和反向代理的区别:正向代理隐藏真实客户端,反向代理隐藏真实服务端,图示: 2.cookie跨域问题 因为cookie存在跨域问题,其中一个解决方法是,设置 ...

  9. Iframe和Frame中实现cookie跨域的方法(转载)

    在Iframe和Frame中默认是不支持Cookie跨域的,但通过设置P3P协议相关的响应头可以解决这一问题.关于p3p协议: P3P: Platform for Privacy Preference ...

随机推荐

  1. Mac 外接 Dell 4K 显示器字体模糊解决办法

    Mac 外接 Dell 4K 显示器字体模糊解决办法 mac mini mbp 2020 refs https://zhuanlan.zhihu.com/p/52100804 xgqfrms 2012 ...

  2. SCSS 复用 class 样式

    SCSS 复用 class 样式 @mixin & @include 复用的变量名称,不可以是 .class 开头️ css-varibale-name .css-class-name Mix ...

  3. 使用 js 实现十大排序算法: 插入排序

    使用 js 实现十大排序算法: 插入排序 插入排序 // 双重循环 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  4. vue & components & props & methods & callback

    vue & components & props & methods & callback demo solution 1 & props & data ...

  5. search cascade select & AntD

    search cascade select & AntD Antd https://ant.design/components/cascader-cn/#components-cascader ...

  6. USDN稳定币应用区块链旅游业

    比特币是区块链1.0时代的标志性产品,稳定币则是区块链2.0时代的标志性产品.在稳定币鼻祖USDT爆出"超发"新闻后曾引发市场的动荡,之后新兴稳定币如春笋般涌现.据不完全同济,目前 ...

  7. 苏黎世财经对话区块链专家,NGK如何利用时间价值实现自身的垂直扩张?

    近日,苏黎世财经日报联合法兰西金融等多家知名媒体,专访了NGK. 苏黎世财经日报专栏记者玛科尔德表示,随着NGK DeFi的明星代币BGV登上去中心化金融的舞台,它千倍的收益率让生态投资者趋之若鹜. ...

  8. NLog整合Exceptionless

    前言 在实际的.Net Core相关项目开发中,很多人都会把NLog作为日志框架的首选,主要是源于它的强大和它的扩展性.同时很多时候我们需要集中式的采集日志,这时候仅仅使用NLog是不够的,NLog主 ...

  9. java自学第5期——Object、Date、Calender、System、StringBuilder、基本类型包装类

    一.Object类 作用:对象操作 位置:java.lang.Object 方法: public String toString() :返回对象的字符串表示形式. public boolean equ ...

  10. 上天的源码要不要——GitHub 热点速览 v.21.08

    作者:HelloGitHub-小鱼干 前几天,"机智号" 所用的飞行软件框架 F´ 被 NASA 开源了,想看 F´ 这个嵌入式的代码不妨考虑下 Sourcetrail 这个神器, ...