记一次 CORS 跨域请求实践

前端 ajax 跨域请求应该算是每个前端都应该有的 “理论基础”, 之所以说是 “理论基础” 是因为这是一道经典的面试题,所以基本每个前端都应该知道对应的解决方案。然而实际开发中其实很少会遇到跨域的情况,毕竟大多数的情况下都是访问同一个域内的东西。

先说说面试的答案吧,解决前端跨域请求主要有以下几种方案:

  1. JSONP 请求
  2. CORS 通过服务端配置 Access-Control-Allow-Origin 响应头实现跨域
  3. 后端设置代理 proxy 跨域

其他还有 document.domain, window.name 等方案,由于实际使用场景不大,暂不做分析。

JSONP 的原理是利用 script 标签的加载不受同源策略的限制,动态的加载一个 <script>callback(data);</script> 标签并执行对应的 callback 来实现的。记住 JSONP 返回的其实是一个 callback 的函数调用,调用的参数(data)由后端服务器根据传入参数(url.query)和业务场景进行填充。

Access-Control-Allow-Origin 跨域方案更像是一个协商机制,对于跨域的请求,服务端在收到请求的时候判断请求是不是来源于被允许的域,如果是就设置对应的响应头告诉客户端该请求是被允许的,而客户端拿到响应头会去解析 Access-Control-Allow-Origin 判断这个跨域请求是不是被允许的,从而决定这个跨域请求的结果是否是合法的。(个人理解,如有不当之处还请指出)

proxy 代理的方案主要是将请求发送到同域的后端服务器上,再由同域的后端去像对应的目标服务器获取数据,前端代码只与同域的服务器进行数据交换,跨域发生在同域的服务器与目标服务器之间,对于前端请求而言不存在跨域。

本次项目中我们最终选择的是第二种方案——设置 Access-Control-Allow-Origin,主要有以下两个原因:

  1. JSONP 能解决大多数的跨域场景,但无法实现 post 请求(实际只是加载一个 script 标签),而且请求的参数也只能在 url 中传递。而我们的业务场景中有不可避免的 post 请求,所以无法满足需求。
  2. 在本来就有同域 node 端服务支持的情况下,使用 proxy 方案应该是最优方案,但由于资源不足,时间紧等原因最后放弃了该方案。

接下来说说遇到的一些问题:
问题 1:设置响应头为 Access-Control-Allow-Origin: * 无效
最开始后端同学在请求的响应头中设置了 Access-Control-Allow-Origin: *,但是实际联调中 网络请求成功了,在 network 面板下也看到了对应的响应数据,但是程序里面的请求始终无法成功,控制台下提示 * 的值不被允许(当时只是叫后端同学改成返回对应的域,并没有去深究为什么 * 不行,后来看到是因为请求带上了 cookie(做用户身份认证),这种情况下服务端响应头需要设置 Access-Control-Allow-Credentials : true 来运行客户端携带证书式访问,而此时 Access-Control-Allow-Control: * 是不被允许的)
后端通过请求 origin 设置 响应 对应 Access-Control-Allow-Origin 可参考这里: Access-Control-Allow-Origin 跨域设置多域名 Java 端逻辑上也是类似的。

问题 2:在 nginx 层和业务代码中都设置 Access-Control-Allow-Origin 跨域依旧存在
通过动态在业务代码中设置 Access-Control-Allow-Origin 对应允许跨域的响应头,已经能把请求跑通,完成跨域的操作了,但是如果遇到用户登录信息失效的情况就又有问题了,此时的流程为 request --> nginx --> filter --> response 用户登录信息失效的时候实际还未进入到对应接口的业务逻辑里面(响应里面未设置 Access-Control-Allow-Origin头),虽然后端返回了 302 的信息但又跨域了,所以前端请求又错误了,而且并不能拿到具体的错误内容。所以后端的跨域响应头设置得提前。
于是我们在 nginx 层也添加了相同的头信息,此时的流程是 request --> nginx -(添加Access头)-> filter --> 业务代码 -(添加Access头)-> response,在这里我们设置了两个相同的 Access-Control-Allow-Origin 头,
如何解决呢,既然我们设置一个 Access-Control-Allow-Origin 的时候可以跑通,现在我们去掉一个多余的头信息设置应该也能跑通,去掉哪一个呢?显然应该是业务代码里面那个,而应该在 nginx 上做,保证每个请求都正确的设置 Access-Control-Allow-Origin 头信息。

最后说说在后端接口支持跨域前如何先联调起来:
此时由于我们的已经能拿到后端返回的数据了(network面板上能看到数据了),之所以现在我们代码中依然拿不到数据其实是因为浏览器的安全策略阻止了代码中对响应的访问,所以如果我们能临时的关闭浏览器的安全策略是否就能拿到对应的数据了呢,测试完过后答案是肯定的。
关闭浏览器安全策略方案可参考这里:chrome disable-web-security 关闭安全策略 解决跨域,mac 的情况下 --user-data-dir 参数需要指定一个文件目录。

该方法只限于联调阶段,实际场景中不可能让用户以禁止安全策略的方式运行浏览器访问我们的站点。

参考资料:

  1. FatDong1/cross-domain
  2. MDN-HTTP访问控制(CORS)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,585评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,923评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,314评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,346评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,718评论 3 291
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,828评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,020评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,758评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,486评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,722评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,196评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,546评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,211评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,132评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,916评论 0 200
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,904评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,758评论 2 274

推荐阅读更多精彩内容

  • 题目1.什么是同源策略? 同源策略(Same origin Policy): 浏览器出于安全方面的考虑,只允许与本...
    FLYSASA阅读 1,665评论 0 6
  • 1. 所谓跨域 跨域是一种浏览器同源安全策略,也即浏览器单方面限制脚本的跨域访问。很多人可能误认为资源跨域时无法请...
    blurooo阅读 6,114评论 11 54
  • 1. 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScri...
    cbw100阅读 6,220评论 2 86
  • XMLHttpRequest的跨域请求 动态添加一个标签,而script标签的src属性是没有跨域的限制的。这样说...
    葛高召阅读 22,176评论 0 0
  • 不知在多少个不经意的瞬间,我们总是会有意无意的,收到他人给自己下的一些看似一本正经的结论。当我们对这些结论产生质疑...
    悄然Edward阅读 191评论 0 2