定义
- 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求(或者说服务器正常返回,但被浏览器拦截了)。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。
使用场景
由
XMLHttpRequest
或 Fetch 发起的跨域 HTTP 请求。- Web 字体 (CSS 中通过
@font-face
使用跨域字体资源 - WebGL 贴图
使用
[drawImage](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage)
将 Images/video 画面绘制到 canvas功能
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
- 规范要求,对于非简单请求,浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。
- 在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
简单请求的定义
若满足下文所有条件,则将该请求视为简单请求:
- 使用以下方法之一:
- GET
- HEAD
- POST
- 除了用户代理自动设置的首部字段(Connection、User-Agent)和在Fetch中被定义为 禁用首部名称 的头部(下文)之外,不存在除:
[Accept](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept)
Accept-Language
Content-Language
Content-Type
(需要注意额外的限制)[DPR](http://httpwg.org/http-extensions/client-hints.html#dpr)
[Downlink](http://httpwg.org/http-extensions/client-hints.html#downlink)
[Save-Data](http://httpwg.org/http-extensions/client-hints.html#save-data)
[Viewport-Width](http://httpwg.org/http-extensions/client-hints.html#viewport-width)
[Width](http://httpwg.org/http-extensions/client-hints.html#width)
之外的头部。
- Content-Type 的值为以下三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
- 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
- 请求中没有使用 ReadableStream 对象。
Fetch中被定义为 禁用首部名称 的头部
语雀内容预检请求(preflight)
- 正如上文所说,非简单请求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
- 预检请求中,通常带有两个字段:
- Access-Control-Request-Method 告知服务器,要使用什么方式实际请求
- Access-Control-Request-Headers 告知服务器,实际请求会携带的参数是什么
预检请求的返回体中,通常带有三个字段:
客户端可以通过设置 XMLHttpRequest 的 withCredentials 为true,从而向服务端发送cookie。这需要配合服务端响应的头部携带 Access-Control-Allow-Credentials: true , 不然浏览器将不会把响应内容返回给请求的发送者。
- 对于附带身份凭证,比如请求头部带了cookie的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。
CORS新增头部
响应
Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
- origin 参数的值指定了允许访问该资源的外域 URI。
- 对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。
如果服务端指定了具体的域名而非“*”,那么响应首部中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的源站返回不同的内容。
Access-Control-Expose-Headers
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
例如在示例中,浏览器就可以额外访问到
X-My-Custom-Header, X-Another-Custom-Header
了Access-Control-Max-Age
Access-Control-Max-Age: <delta-seconds>
指定了preflight请求的结果能够被缓存多久
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials: true
- 指定了当浏览器的 credentials 设置为 true 时是否允许浏览器读取 response 的内容。当用在对 prefligh t预检测请求的响应中时,它指定了实际的请求是否可以使用 credentials 。
请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。
Access-Control-Allow-Methods
Access-Control-Allow-Methods: <method>[, <method>]*
用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。
Access-Control-Allow-Headers
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
- 用于预检请求的响应。其指明了实际请求中允许携带的首部字段。
请求
Origin
Origin: <origin>
- 表明预检请求或实际请求的源站。
- 不包含任何路径信息,只是服务器名称。
注意,在所有访问控制请求(Access control request)中,Origin 首部字段总是被发送。
Access-Control-Request-Method
Access-Control-Request-Method: <method>
用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。
Access-Control-Request-Headers
Access-Control-Request-Headers: <field-name>[, <field-name>]*
- 用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。