same origin policy & CORS --- 同源策略 与 跨域资源共享

跨域对于前端来讲是个耳熟的字眼,在日常工作和面试中经常出现。
本文介绍了同源策略CORS跨域资源共享实际开发中如何处理跨域这几个方面。

前端开发过程中,你肯定见过这个报错。Access to fetch at 'https://m.demo.com' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. 这就是跨域请求被浏览器拦截没跑了。

same origin policy & CORS

同源策略 (same origin policy),是浏览器最核心、最基本的安全功能之一。它限制了从一个源(origin)加载的文档如何与另外一个源的资源进行交互。
Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。
更详细的说,是浏览器对在脚本内跨源发起的 http请求 的response结果进行了拦截
想象一下,如果没有这个策略限制,就会发生某一个源随意调用其他源的接口获取他人数据,篡改他们数据……等等肥肠价值观警告的事情。

该策略常见的三种情况:

  • Cross-origin writes 跨域写 例如链接links、重定向、表单提交……
  • Cross-origin embedding 资源嵌入 比如 script 、link、img、video等标签嵌入资源
  • Cross-origin reads 跨域读 但可通过嵌入巧妙绕过

同源就是指两个页面的协议、主机、端口号(如果有)三者皆一致。 当一个资源a从一个与该资源a所在服务器a不同协议、域或端口 的服务器b上请求另一个资源b,这就发起了一个跨域HTTP请求。

exp:http:/ / www. baidu. com:80 http即协议,www. baidu . com即主机,80即端口号。

但有时候开发中,确实存在这样、那样的跨域资源获取需求。这就要讲到跨域资源共享(Cross-Origin Resource Sharing) ,允许服务器声明 哪些 有权限通过浏览器 访问哪些资源。给我们争取一个跨域请求的机会。
借用个栗子,客户端发起一个simple request get请求:

image

  • Client request header请求头 get 请求获取 /resources/public-data/ 下的资源
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/\*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http:\/\/foo.example\/examples\/access-control\/simpleXSInvocation.html
Origin: http:\/\/foo.example
  • Server response header 响应头
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61 
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]

服务端返回的 Access-Control-Allow-Origin: *表明,该资源可被任意外域访问。
ps:如果服务器仅希望某个源(比如http:/ /examples.com)可以访问其资源,只需设置 Access-Control-Allow-Origin: http:/ /examples.com 。如果希望仅允许GET请求或多种请求,则可设置 Access-Control-Allow-Methods:GET, POST, ……

解决方法

已知的一些方法在生产环境几乎都需要server进行配合,本地开发的话前端是完全可以自行绕过跨源问题。

方法如下(前四种适用于生产环境):
1、后端在reponse header中添加 Access-Control-Allow-Origin: xxx允许跨源请求。

exp,http: //hello-world.example 想访问 http: //example.com 的资源。 http: //example.com 在response header 中添加 Access-Control-Allow-Origin: http: //hello-world.example
当然 也可以一了百了添加 Access-Control-Allow-Origin: * ,只要你确保不会产生其他副作用。

2、前端使用JSONP

像一些资源标签(如img,video,script……)允许跨源资源嵌入,即标签的src是允许嵌入跨源资源的。jsonp其实就是通过 script src 传递参数(请求参数、约定的callback name)给服务器,服务器将返回数据包裹在回调函数中,直接在脚本中进行调用达到跨域获取资源数据的效果。

3、document.domain,允许子域安全访问其父域。

document.domain 的值可以设置为其当前域或其当前域的父域。如果将其设置为其当前域的父域,则这个较短的父域将用于后续源检查。(设置后当前域端口号会被重写为Null)
举个栗子,假设http: //demo.example.com中有一个脚本执行了 document.domain = 'example.com'; 那么浏览器将会通过对http: //company.com/dir/page.html (http: //company.com/dir/page.html 也必须设置document.domain = 'example.com'; 以重置端口号)资源的同源检测。

4、OPTIONS预检请求

preflight request 是一个包含了:Access-Control-Request-MethodAccess-Control-Request-Headers,以及一个 Origin 首部的options请求。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。
对于可能对服务器数据产生副作用的请求(GET以外,搭配某些MIME type的请求),浏览器都会先发出一个预检请求,以监测服务器是否允许该类型的请求。确认允许后,才会发出实际请求。
OPTIONS 请求用于获取目的资源所支持的通信选项。

5、如果是本地开发,还可使用chrome - Allow CORS: Access-Control-Allow-origin插件允许跨域,或命令行 open -a "Google Chrome" --args --disable-web-security --user-data-dir

chrome插件的做法应该就是在 response 达到浏览器前,在 response header 中添加了 Access-Control-Allow-Origin 和 Access-Control-Allow-Methods 两个字段来达到允许跨域资源共享的原理。

6、webpack proxy可以在开发环境代理跨域请求,但build打包后,代理是不生效的,请注意这点。

参考资料

CORS:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
浏览器同源策略:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy
Document.domain:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/domain
W3C Cross-Origin Resource Sharing:https://www.w3.org/TR/cors/

如有遗漏的方法 欢迎补充讨论 ~

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

推荐阅读更多精彩内容