Cross-Origin Resource Sharing - CORS
(AKA Cross-Domain AJAX request) 是大多数 web 开发者可能会遇到的问题,根据 Same-Origin-Policy,浏览器将客户端 JavaScript 限制在安全沙箱中,通常 JS 无法直接与远程服务器通信来自不同的域。过去开发者创造了许多棘手的方式来实现跨域资源请求,最常用的方式是:
- 使用 Flash/Silverlight 或服务器端作为“代理”与远程通信。
- 带填充的 JSON ( JSONP )。
- 在 iframe 中嵌入远程服务器并通过 fragment 或 window.name 进行通信,请参阅此处。
那些棘手的方法或多或少都有一些问题,例如 JSONP 如果开发人员简单地“评估”它可能会导致安全漏洞,以及上面的 #3,虽然它有效,但两个域之间应该建立严格的契约,既不灵活也不优雅恕我直言:)
W3C 引入了跨域资源共享 (CORS) 作为标准解决方案,以提供一种安全、灵活且推荐的标准方法来解决此问题。
机制
从高层次我们可以简单地认为 CORS 是来自域 A 的客户端 AJAX 调用和域 B 上托管的页面之间的契约,典型的跨域请求/响应将是:
DomainA AJAX 请求标头
Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com
DomainB 响应头
Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive
我在上面标记的蓝色部分是内核事实,“Origin”请求标头“表示跨域请求或预检请求的来源”,“Access-Control-Allow-Origin”响应标头表示此页面允许远程请求来自DomainA(如果值为 * 表示允许来自任何域的远程请求)。
正如我上面提到的,W3 建议浏览器在提交实际跨域 HTTP 请求之前实现“预检请求”,简而言之,它是一个 HTTPOPTIONS
请求:
OPTIONS DomainB.com/foo.aspx HTTP/1.1
如果 foo.aspx 支持 OPTIONS HTTP 动词,它可能会返回如下响应:
HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json
仅当响应中包含“Access-Control-Allow-Origin”且值为“*”或包含提交CORS请求的域时,满足此强制条件浏览器才会提交实际的跨域请求,并缓存结果在“预检结果缓存”中。
三年前我写了一篇关于 CORS 的博客:AJAX 跨域 HTTP 请求