跨域资源共享(CORS不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
- Fetch
- Web 字体 (CSS 中通过
因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用。
- WebGL 贴图
drawImage
- CSSOM)
CORS 预检请求。本文称这样的请求为“简单请求”。
若请求满足所有下述条件,则该请求可视为“简单请求”:
- 使用下列方法之一:
- Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为:
text/plain
multipart/form-data
application/x-www-form-urlencoded
- 请求中的任意
XMLHttpRequestUpload
XMLHttpRequestUpload
注意:
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/public-data/'; function callOtherDomain() { if(invocation) { invocation.open('GET', url, true); invocation.onreadystatechange = handler; invocation.send(); } }
客户端和服务器之间使用 CORS 首部字段来处理跨域权限:

1 GET /resources/public-data/ HTTP/1.1 2 Host: bar.other 3 User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 5 Accept-Language: en-us,en;q=0.5 6 Accept-Encoding: gzip,deflate 7 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 8 Connection: keep-alive 9 Referer: http://foo.example/examples/access-control/simpleXSInvocation.html 10 Origin: http://foo.example 11 12 13 HTTP/1.1 200 OK 14 Date: Mon, 01 Dec 2008 00:23:53 GMT 15 Server: Apache/2.0.61 16 Access-Control-Allow-Origin: * 17 Keep-Alive: timeout=2, max=100 18 Connection: Keep-Alive 19 Transfer-Encoding: chunked 20 Content-Type: application/xml 21 22 [XML Data]
http://foo.exmaple
。
Access-Control-Allow-Origin
(第 16 行)。
Access-Control-Allow-Origin: *
任意外域访问。
如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Origin
"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响
请求满足下述任一条件时,即应首先发送预检请求:
- 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
application/x-www-form-urlencoded
multipart/form-data
text/plain
- 请求中的
XMLHttpRequestUpload
- 请求中使用了对象。
如下是一个需要执行预检请求的 HTTP 请求:
1 var invocation = new XMLHttpRequest(); 2 var url = 'http://bar.other/resources/post-here/'; 3 var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; 4 5 function callOtherDomain(){ 6 if(invocation) 7 { 8 invocation.open('POST', url, true); 9 invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); 10 invocation.setRequestHeader('Content-Type', 'application/xml'); 11 invocation.onreadystatechange = handler; 12 invocation.send(body); 13 } 14 } 15 16 ......

1.OPTIONS /resources/post-here/ HTTP/1.1 2.Host: bar.other 3.User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 4.Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 5.Accept-Language: en-us,en;q=0.5 6.Accept-Encoding: gzip,deflate 7.Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 8.Connection: keep-alive 9.Origin: http://foo.example 10.Access-Control-Request-Method: POST 11.Access-Control-Request-Headers: X-PINGOTHER, Content-Type 12. 13. 14.HTTP/1.1 200 OK 15.Date: Mon, 01 Dec 2008 01:15:39 GMT 16.Server: Apache/2.0.61 (Unix) 17.Access-Control-Allow-Origin: http://foo.example 18.Access-Control-Allow-Methods: POST, GET, OPTIONS 19.Access-Control-Allow-Headers: X-PINGOTHER, Content-Type 20.Access-Control-Max-Age: 86400 21.Vary: Accept-Encoding, Origin 22.Content-Encoding: gzip 23.Content-Length: 0 24.Keep-Alive: timeout=2, max=100 25.Connection: Keep-Alive 26.Content-Type: text/plain
预检请求完成之后,发送实际请求:
POST /resources/post-here/ 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 X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: http://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: http://foo.example Pragma: no-cache Cache-Control: no-cache <?xml version="1.0"?><person><name>Arun</name></person> HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plain [Some GZIP'd payload]
预检请求
”。
该方法不会对服务器资源产生影响。 预检请求中同时携带了下面两个首部字段:
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
首部字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法。
Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求首部字段:
X-PINGOTHER 与 Content-Type。
服务器据此决定,该实际请求是否被允许。
Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
首部字段表明服务器允许客户端使用
POST,
OPTIONS
与X-PINGOTHER
。
Access-Control-Max-Age
大多数浏览器不支持针对于预检请求的重定向。如果一个预检请求发生了重定向,浏览器将报告错误:
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
在浏览器的实现跟上规范之前,有两种方式规避上述报错行为:
- 在服务端去掉对预检请求的重定向;
- 将实际请求变成一个简单请求。
如果上面两种方式难以做到,我们仍有其他办法:
- Response.urlXHR.responseURL)以判断真正的预检请求会返回什么地址。
- 发出另一个请求(真正的请求),使用在上一步通过Response.urlXMLHttpRequest.responseURL获得的URL。
Fetch不会发送身份凭证信息。
的某个特殊标志位。
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/credentialed-content/'; function callOtherDomain(){ if(invocation) { invocation.open('GET', url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); } }
withCredentials 标志设置为 true,

客户端与服务器端交互示例如下:
1 GET /resources/access-control-with-credentials/ HTTP/1.1 2 Host: bar.other 3 User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 5 Accept-Language: en-us,en;q=0.5 6 Accept-Encoding: gzip,deflate 7 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 8 Connection: keep-alive 9 Referer: http://foo.example/examples/credential.html 10 Origin: http://foo.example 11 Cookie: pageAccess=2 12 13 14 HTTP/1.1 200 OK 15 Date: Mon, 01 Dec 2008 01:34:52 GMT 16 Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2 17 X-Powered-By: PHP/5.2.6 18 Access-Control-Allow-Origin: http://foo.example 19 Access-Control-Allow-Credentials: true 20 Cache-Control: no-cache 21 Pragma: no-cache 22 Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT 23 Vary: Accept-Encoding, Origin 24 Content-Encoding: gzip 25 Content-Length: 106 26 Keep-Alive: timeout=2, max=100 27 Connection: Keep-Alive 28 Content-Type: text/plain 29 30 31 [text/plain payload]
: true(
第 19 行),则响应内容不会返回给请求的发起者。
Access-Control-Allow-Origin 的值为“*”。
http://foo.example,则请求将成功执行。
另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。
Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
Access-Control-Expose-Headers
在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
这样浏览器就能够通过getResponseHeader访问X-My-Custom-Header
X-Another-Custom-Header
。
Access-Control-Max-Age
Access-Control-Max-Age: <delta-seconds>
delta-seconds
Access-Control-Allow-Credentials
credentials
设置为true时是否允许浏览器读取response的内容。
当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials
。
请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods
Access-Control-Allow-Methods: <method>[, <method>]*
Access-Control-Allow-Headers
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
略
做记录
参考网址
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS