CORS 跨域

1.简介

跨域资源共享(CORS),允许浏览器向跨域服务器发出XMLHttpRequest或Fetch请求,避免了浏览器同源策略的限制。CORS需要浏览器和服务器同时支持。目前除了IE10以下的浏览器都已支持。
浏览器发现请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,实现CORS通信的关键是服务器。
CORS请求分成:简单请求(simple request)和预检请求(Preflighted requests)。

满足下面条件就属于简单请求:
1.请求方法是这3种之一: HEAD, GET, POST
2.HTTP的头信息不超出以下字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type(只限于3个值:application/x-www-form-urlencoded、multipart/form-data、text/plain)
  • 详细 Fetch 规范

3.请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
4.请求中没有使用 ReadableStream 对象。

2.简单请求

浏览器发现简单请求,就在头信息中添加一个Origin字段(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

服务器不同意:返回正常http响应,头信息没有Access-Control-Allow-Origin字段,抛出错误被onerror捕获,注意这里的状态码可能是200。

服务器同意:返回响应头信息多出几个字段:

  1. Access-Control-Allow-Origin(必选):Origin的值或* 。
  2. Access-Control-Allow-Credentials(可选):布尔值,是否允许发送Cookie。
  3. Access-Control-Expose-Headers(可选):XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段,要拿其他字段需要在这指定。

withCredentials 属性:要发送Cookie,Credentials设为true,AJAX中打开withCredentials属性,Origin不用 * 号,用具体同源信息。

3.预检请求

预检请求:先增加一次查询请求(查许可名单)。应对请求方法是PUT或DELETE或者Content-Type字段的类型是application/json。

预检请求方法:OPTIONS(用来询问),
包含Origin字段,
包含 Access-Control-Request-Method:用到哪些HTTP方法,
包含 Access-Control-Request-Headers:额外发送的头信息字段。

预检请求的响应:检查上述字段,确认是否允许,
浏览器否定了预检请求,抛出错误。(XXX is not allowed by XXX Origin)

其他CORS相关字段:

  1. Access-Control-Allow-Methods(必须): 所有支持的方法。
  2. Access-Control-Allow-Headers(必须):支持的所有头信息字段。
  3. Access-Control-Allow-Credentials: true(与简单请求含义相同)。
  4. Access-Control-Max-Age: 预检请求的有效期(秒),此期间,不用发出另一条预检请求。

预检通过后,每次CORS与正常请求相同了。请求中Origin字段是浏览器自动添加的。
响应中Access-Control-Allow-Origin字段每次必须包含。

4.对比JSONP

都是跨域。JSONP只支持GET请求,支持老浏览器,可向没设置CORS的网站请求数据。CORS支持所有类型的HTTP请求。

其他:通过document.domain跨域,通过location.hash跨域,通过HTML5的postMessage方法跨域,通过window.name跨域。(中间件跨域,服务器代理跨域,Flash URLLoader跨域,动态创建script标签(简化版本的jsonp))。

注意:某些版本的Android浏览器中,因为缓存的原因,第一次进行跨域请求是正常的,但是第二次进行的时候则会失效,对于这个问题,可以通过在Header中增加Cache-Control: no-cache 阻止缓存的方式来解决这个问题。

Reference:
http://stackoverflow.com/questions/1652850/android-webview-cookie-problem
https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
http://www.ruanyifeng.com/blog/2016/04/cors.html