CORS
CORS(Cross-Origin Resource Sharing,跨源资源共享),也有译作跨域资源共享。
CORS 机制允许 Web 应用服务器控制跨源访问,从而使跨源数据传输得以安全进行。
请求标头
无须手动设置请求标头。当开发者使用XHR、fetch发起跨源请求时,浏览器会自动设置标头、发送预检请求。
Origin
Origin: <origin>
Origin 参数的值为源站 URL origin。它不包含任何路径信息,只是服务器名称。
Access-Control-Request-Method
请求头 Access-Control-Request-Method
出现于预检请求中,用于通知服务器在真正的请求中会采用哪种 HTTP 方法。
因为预检请求所使用的方法总是 OPTIONS
,与实际请求所使用的方法不一样,所以这个请求头是必要的。
Access-Control-Request-Method: <method>
Access-Control-Request-Method
请求头 Access-Control-Request-Method
出现于预检请求中,用于通知服务器在真正的请求中会采用哪种 HTTP 方法。
因为预检请求所使用的方法总是 OPTIONS
,与实际请求所使用的方法不一样,所以这个请求头是必要的。
Access-Control-Request-Method: <method>
若服务端允许,则应返回响应标头
Access-Control-Allow-Methods: <method>[, <method>]*
Access-Control-Request-Headers
请求头 Access-Control-Request-Headers
出现于预检请求中,用于通知服务器在真正的请求中会采用哪些请求头。
Access-Control-Request-Headers: <field-name>[, <field-name>]*
若服务端允许,则应返回响应标头
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
响应标头
服务器返回的 HTTP 响应头,可以控制浏览器允许这些源访问加载自己的资源。
Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
允许指定的源访问资源,或对于不需要带身份凭证的请求,指定*
允许任意源请求。
Access-Control-Expose-Headers
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
对于访问控制请求,浏览器默认只让JS访问Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
这些标头,想要访问更多标头需要服务器配置此响应标头。
Access-Control-Max-Age
Access-Control-Max-Age: <delta-seconds>
指定预检请求的结果能够被浏览器缓存多久。
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials: true
指定浏览器附带凭证的请求,对应的响应是否让JS能够访问。
简单请求
简单请求不会触发 CORS 预检请求。 对简单请求的条件限制,简单理解就是 <form>
元素能够发出的请求。
当请求满足下述任一条件时,即应首先发送预检请求:
- 使用了指定任一 HTTP 方法:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
- 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段
Content-Type
的值不属于:application/x-www-form-urlencoded
、multipart/form-data
、text/plain
- 请求中的
XMLHttpRequestUpload
对象注册了任意多个事件监听器 - 请求中使用了
ReadableStream
对象
预检请求
不满足简单请求条件的,或者说不能通过<form>
元素发出的请求,浏览器就必须首先使用 OPTIONS
方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
使用预检请求而不是直接发送实际请求的好处
- 一是可以避免在服务端错误设置CORS时处理了实际请求,例如删除数据。
- 二是可以控制浏览器阻止发送不允许的请求、访问响应数据中的敏感信息如自定义标头。
预检请求是由浏览器自动发出的,浏览器开发者工具中看不到预检请求,需要在服务器查看和处理。
一个预检请求和服务端响应的例子
OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
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
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive