CORS讲解

匿名 (未验证) 提交于 2019-12-02 22:06:11

跨域资源共享(CORS不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求

和 HTTP 认证相关数据)。

CORS 预检请求。本文称这样的请求为“简单请求”。

若请求满足所有下述条件,则该请求可视为“简单请求”:

注意:

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

Access-Control-Allow-Origin: *任意外域访问。

如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:

Access-Control-Allow-Origin: http://foo.example

Access-Control-Allow-Origin

"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响

请求满足下述任一条件时,即应首先发送预检请求:

如下是一个需要执行预检请求的 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

在浏览器的实现跟上规范之前,有两种方式规避上述报错行为:

  • 在服务端去掉对预检请求的重定向;
  • 将实际请求变成一个简单请求。

如果上面两种方式难以做到,我们仍有其他办法:

FetchHTTP cookies

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-HeaderX-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

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

文章来源: CORS讲解
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!