出于安全考虑,浏览器会阻止从脚本内发起的跨域HTTP请求,即使用XMLHttpRequest发起的HTTP请求(AJAX)只能发送到自己的域。CORS就是一个用来允许服务器进行跨域资源访问的一个W3C标准,全称“跨域资源共享”(Cross-origin resource sharing)。

CORS需要客户端和服务器同时支持,目前所有的浏览器(客户端,低于IE10的不支持)都支持该机制。

跨域资源共享通常用于以下场景:

  • XMLHttpRequestFetch发起的跨域HTTP请求。
  • Web字体
  • WebGL
  • CSS或者Script

CORS跨域请求分为两类:简单请求和预检请求

简单请求

满足条件:

原理:

简单请求直接在头信息中添加Origin字段来处理跨域权限:

一个简单的跨域请求例子:

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

Origin字段指定了要请求的地址。即http://api.bob.com。

下面是服务器的响应信息:

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

返回头信息中的Access-Control-Allow-Origin指定了该资源可被哪些外域访问,*表示该资源可被任意外域访问,如果服务端仅允许来自 http://foo.example 的访问,该首部字段应该指定http://foo.example

若如此,该资源将不能被除http://foo.example之外的任何资源访问。

预检请求

预检请求在对服务器进行跨域访问之前,必须先使用OPTIONS方法发起一个预检请求到该服务器来确认该服务器是否允许跨域请求。

满足下列任一请求时,则必须先发送预检请求:

下面是一个预检请求的例子:

var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.send();

上面的例子使用了PUT方法并使用了自定义头信息X-Custom-Header,而且请求的Content-Type为application/xml。因此,在发送该请求前会由浏览器先发送“预检请求”。

下面是浏览器发送的预检请求:

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

预检请求使用的方法是OPTIONS,Origin字段指定了要请求的源。OPTIONS是HTTP/1.1协议中定义的方法,用以从服务器获取更多信息。预检请求还会携带下列两个字段:

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
(1)Access-Control-Request-Method

该字段用于告知服务器该请求使用的何种方法,例如上述代码中华使用的POST方法

(2)Access-Control-Request-Headers

该字段用于告知服务器该请求所携带的额外的自定义请求字段,服务器来判断该请求是否被允许。

下面是该请求的响应信息:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 86400

(1)Access-Control-Allow-Methods

该字段表明该服务器允许客户端使用的请求方法,如GET, POST, PUT。

(2)Access-Control-Allow-Headers

该字段表明了服务器允许请求中携带的额外字段

(3)Access-Control-Max-Age

该字段表明了此次响应的有效时间,例如86400,也就是一天。在有效时间内,浏览器无需为同一请求再次发送预检请求。