跨域资源共享 CORS

简介

CORS是一个W3C规范,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源运用的限定。

CORS须要浏览器和服务器同时支撑。现在,一切浏览器都支撑该功用,IE浏览器不能低于IE10。

全部CORS通讯历程,都是浏览器自动完成,不须要用户介入。关于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码完整一样。浏览器一旦发明AJAX请求跨源,就会自动增添一些附加的头信息,偶然还会多出一次附加的请求,但用户不会有觉得。

因而,完成CORS通讯的症结是服务器。只需服务器完成了CORS接口,就能够跨源通讯。

两种请求

浏览器将CORS请求分红两类:简朴请求(simple request)和非简朴请求(not-so-simple request)。

只需同时满足以下两大前提,就属于简朴请求。

(1) 请求要领是以下三种要领之一:
HEAD
GET
POST
(2)HTTP的头信息不超越以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

通常不同时满足上面两个前提,就属于非简朴请求。浏览器对这两种请求的处置惩罚,是不一样的。

简朴请求

关于简朴请求,浏览器直接发出CORS请求。具体来讲,就是在头信息当中,增添一个Origin字段。

下面是一个例子,浏览器发明此次跨源AJAX请求是简朴请求,就自动在头信息当中,增添一个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字段用来讲明,本次请求来自哪一个源(协定 + 域名 + 端口)。服务器依据这个值,决议是不是赞同此次请求。

假如Origin指定的源,不在允许范围内,服务器会返回一个一般的HTTP回应。浏览器发明,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就晓得出错了,从而抛出一个毛病,被XMLHttpRequest的onerror回调函数捕捉。注重,这类毛病没法经由过程状况码辨认,由于HTTP回应的状况码有多是200。

假如Origin指定的域名在允许范围内,服务器返回的相应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的头信息当中,有三个与CORS请求相干的字段,都以Access-Control-开首。
(1)Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,示意接收恣意域名的请求。

(2)Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,示意是不是允许发送Cookie。默许情况下,Cookie不包含在CORS请求当中。设为true,即示意服务器明白允许,Cookie能够包含在请求中,一同发给服务器。这个值也只能设为true,假如服务器不要浏览器发送Cookie,删除该字段即可。

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()要领只能拿到6个基础字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。假如想拿到其他字段,就必须在Access-Control-Expose-Headers内里指定。上面的例子指定,getResponseHeader(‘FooBar’)能够返回FooBar字段的值。

withCredentials 属性

上面说到,CORS请求默许不发送Cookie和HTTP认证信息。假如要把Cookie发到服务器,一方面要服务器赞同,指定Access-Control-Allow-Credentials字段。

Access-Control-Allow-Credentials: true

另一方面,开发者必须在AJAX请求中翻开withCredentials属性。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

不然,纵然服务器赞同发送Cookie,浏览器也不会发送。或许,服务器请求设置Cookie,浏览器也不会处置惩罚。

然则,假如省略withCredentials设置,有的浏览器照样会一同发送Cookie。这时候,能够显式封闭withCredentials。

xhr.withCredentials = false;

须要注重的是,假如要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明白的、与请求网页一致的域名。同时,Cookie依旧遵照同源政策,只要效服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也没法读取服务器域名下的Cookie。

非简朴请求

预检请求

非简朴请求是那种对服务器有特别请求的请求,比方请求要领是PUT或DELETE,或许Content-Type字段的范例是application/json。

非简朴请求的CORS请求,会在正式通讯之前,增添一次HTTP查询请求,称为”预检”请求(preflight)。

浏览器先讯问服务器,当前网页地点的域名是不是在服务器的允许名单当中,以及能够运用哪些HTTP动词和头信息字段。只要获得一定回复,浏览器才会发出正式的XMLHttpRequest请求,不然就报错。

下面是一段浏览器的JavaScript剧本。

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

上面代码中,HTTP请求的要领是PUT,而且发送一个自定义头信息X-Custom-Header。

浏览器发明,这是一个非简朴请求,就自动发出一个”预检”请求,请求服务器确认能够如许请求。下面是这个”预检”请求的HTTP头信息。

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,示意请求来自哪一个源。

除了Origin字段,”预检”请求的头信息包含两个特别字段。

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP要领,上例是PUT。

(2)Access-Control-Request-Headers

该字段是一个逗号分开的字符串,指定浏览器CORS请求会分外发送的头信息字段,上例是X-Custom-Header。

预检请求的回应

服务器收到”预检”请求今后,搜检了Origin、Access-Control-Request-Method和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
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

上面的HTTP回应中,症结的是Access-Control-Allow-Origin字段,示意http://api.bob.com能够请求数据。该字段也能够设为星号,示意赞同恣意跨源请求。

Access-Control-Allow-Origin: *

假如浏览器否认了”预检”请求,会返回一个一般的HTTP回应,然则没有任何CORS相干的头信息字段。这时候,浏览器就会认定,服务器不赞同预检请求,因而触发一个毛病,被XMLHttpRequest对象的onerror回调函数捕捉。控制台会打印出以下的报错信息。

XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

服务器回应的其他CORS相干字段以下。

Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000

(1)Access-Control-Allow-Methods

该字段必须,它的值是逗号分开的一个字符串,表明服务器支撑的一切跨域请求的要领。注重,返回的是一切支撑的要领,而不单是浏览器请求的谁人要领。这是为了防止屡次”预检”请求。

(2)Access-Control-Allow-Headers

假如浏览器请求包含Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必须的。它也是一个逗号分开的字符串,表明服务器支撑的一切头信息字段,不限于浏览器在”预检”中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简朴请求时的寄义雷同。

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单元为秒。上面效果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不必发出另一条预检请求。

浏览器的一般请乞降回应

一旦服务器经由过程了”预检”请求,今后每次浏览器一般的CORS请求,就都跟简朴请求一样,会有一个Origin头信息字段。服务器的回应,也都邑有一个Access-Control-Allow-Origin头信息字段。

下面是”预检”请求以后,浏览器的一般CORS请求。

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

上面头信息的Origin字段是浏览器自动增添的。

下面是服务器一般的回应。

Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

上面头信息中,Access-Control-Allow-Origin字段是每次回应都一定包含的。

与JSONP的比较

CORS与JSONP的运用目标雷同,然则比JSONP更壮大。

JSONP只支撑GET请求,CORS支撑一切范例的HTTP请求。JSONP的上风在于支撑老式浏览器,以及能够向不支撑CORS的网站请求数据。

from: http://www.ruanyifeng.com/blo…
作者:阮一峰

    原文作者:zer0_li
    原文地址: https://segmentfault.com/a/1190000015907243
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞