跨域资源共享(CORS)

同源策略(W3C规定的)

解决跨域的方式

  • jsonp
  • 反向代理
  • CORS

何为跨域资源共享(CORS)

跨域资源共享是一种机制,它使用额外的HTTP头来告诉浏览器,让运行在一个域下的web应用运行访问不同域下服务器的资源。

什么情况下使用CORS

功能概述

通过设置HTTP首部字段,可以允许服务声明哪些域名可以通过浏览器访问哪些资源。针对可能对服务器数据产生副作用的HTTP请求(特别是除了GET以外的HTTP请求或者某些搭配MIME类型的POST请求),浏览器必须使用OPTIONS发起一个==预检请求==,从而知道服务器端是否允许跨域。服务器端确认之后,才能发起实际的HTTP请求。在预检请求的返回中,服务器端也可以通知客户端,==是否需要携带身份凭证==(包括 Cookies 和 HTTP 认证相关数据)。

简单请求

本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

  • 使用下列方法之一:

    • GET
    • POST
    • HEAD
  • Fetch规范定义了对CORS安全的首部字段集合,不得人为设置该集合之外的其他首部字段。

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (需要注意额外的限制)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • Content-Type 的值仅限于下列三者之一:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • 请求中没有使用 ReadableStream 对象。

预检请求

  • 使用了下面任一 HTTP 方法:

    • PUT
    • DELETE
    • CONNECT
    • OPTIONS
    • TRACE
    • PATCH
  • 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (需要注意额外的限制)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • Content-Type 的值不属于下列之一:
  • 请求中使用了ReadableStream对象。

    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

附带身份凭证的请求

一般而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。

XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies

HTTP首部字段

  • Access-Control-Allow-Origin: *
* 允许所有源发起简单跨域请求
也可以是指定的域名 Access-Control-Allow-Origin: http://foo.example
  • Access-Control-Allow-Methods: POST, GET, OPTIONS
允许使用的HTTP方法
  • Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
允许使用设置额外的头部信息
token
  • Access-Control-Max-Age: 86400
单位秒
在有效时间内,浏览器无须为同一请求再次发起预检请求
  • Access-Control-Allow-Credentials: true
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。
对于携带cookie的跨域请求, Access-Control-Allow-Credentials为true可以将cookie下发给浏览器端,
否则不下发
  • Access-Control-Expose-Headers
在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

Access-Control-Expose-Headers 头让服务器把允许浏览器访问的头放入白名单

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

这样浏览器就能够通过getResponseHeader访问X-My-Custom-Header和 X-Another-Custom-Header 响应头了。









03-05 21:59