HTTP跨域原理
简单请求
请求方式为 GET
、POST
、HEAD
,且仅包含以下 Request Headers:
- Accept
- Accept-Language
- Content-Type(只限于 application/x-www-form-urlencoded、multipart/form-data、text/plain)
- Content-Language
- Last-Event-ID
当发生跨域时,浏览器会携带一个 Origin
头,其包含了协议、域名、端口。
服务器依据该头检查请求是否被允许,若允许向浏览器返回一个正确的 Access-Control-Allow-Origin
,浏览器根据它的值决定是否完成请求(或报错)。
复杂请求
不符合“简单请求”要求的,被称为“复杂请求”。如采用 PUT
、DELETE
请求方式,或 Content-Type
的类型为 application/json
。
复杂请求会在“本次请求”前,先发起一个预检(Preflight)请求,以检查“本次请求”是否被允许。允许则发送,否则直接报错。预检的请求方式为 OPTIONS
,请求头除 Origin
外,还包括:
- Access-Control-Request-Method:指明“本次请求”方式;
- Access-Control-Request-Headers:指明“本次请求”携带的头,逗号分隔;
与“简单请求”一致,同样需要服务器返回正确的 Access-Control-Allow-Origin
头,否则将终止“本次请求”并报错。
CORS Response Headers
共用
Access-Control-Allow-Origin 必选,表示本次请求是否允许跨域。它的值可以与
Origin
一致(多个使用逗号隔开),或为*
。Access-Control-Allow-Credentials 可选,表示是否允许携带 Cookie 等授权信息。可选值
true
、false
,默认false
。 若设置为true
,需要配合 withCredentials 属性一并使用。Access-Control-Expose-Headers 可选,除“安全响应头”外,浏览器可读取的其它响应头列表。如
Content-Encoding
(多个使用逗号隔开),或为*
。 安全响应头包括:Cache-Control、Content-Language、Content-Length、Content-Type、Expires、Last-Modified、Pragma。
复杂请求
Access-Control-Allow-Methods 可选,表示所有被允许的请求方式(逗号分隔)。
Access-Control-Allow-Headers 可选,表示所有被允许的请求头(逗号分隔)。
Access-Control-Max-Age 可选,预检查询的有效期(单位秒),在此期间,不再发起新的预检请求。
三种请求方式
- same-origin:仅允许同源请求
- cors:按照 CORS 策略请求。若非同源,且未响应有效的 CORS Response Headers,则报错
- no-cors:不按照 CORS 策略请求,仅支持“简单请求”。若非同源,返回的 Response 对象 type 为
opaque
,且读不到任何值(status、body、url 等字段均为 zero value)。像是<link>
、<script>
、<img>
、<iframe>
在未指定crossorigin
时都为no-cors