CORS
跨域资源共享,是基于 HTTP 上一个用来解决跨域的方法,需要服务端和浏览器端同时支持
CORS 分为简单请求和非简单请求
简单请求:简单请求只要满足以下两大条件就是简单请求
- 请求方法只能是 GET、POST、HEAD
- 请求头中不超出以下几个字段
accept,
accept-language,
context-type, 其中 content-type 只能是 application/x-www-form-urlencoded、text/plain、multipart/form-data,
Last-Event-ID
否则就视为非简单请求,浏览器对于两种请求处理是不一样的
简单请求
流程
对于简单请求,浏览器直接发出 CORS 请求。具体来说,就是在头信息之中,增加一个 origin 字段,用来标识是哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求
1 | GET/cors HTTP/1.1 |
上面头信息中,origin字段用来说明,本次请求来自哪个源。服务器根据这个值决定是否同意这次请求
如果 Origin 指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。浏览器发现 这个回应的头信息没有包含 Access-Control-Allow-Origin 字段就知道出错了,从而抛出错误。
如果 Origin 指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段
1 | Access-Control-Allow-Origin: http:baidu.com // 该字段是必须的,它的值要么是请求时的 Origin 字段,要么是 * |
非简单请求
非简单请求是那种对服务器有特殊要求的,比如请求方法是 PUT、DELETE,或者 Content-type 是 application/json
非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为 “预检”请求
预检请求:浏览器会先询问服务器,当前网页域名是否在服务器许可名单之中。以及可以使用哪些 HTTP 头部信息,只有得到肯定答复,浏览器才会正式发出请求,否则就报错
预检请求 是通过 OPTIONS 发的,表示这个请求是个询问请求
1 | OPTIONS /cors HTTP/1.1 |
回应预检请求
服务器收到“预检”请求以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段后,确认允许跨域请求,就会做出回应
1 | HTTP/1.1 200 ok |
如果服务器否定了“预检”请求,会返回一个正常的 HTTP 回应,但是没有任何 CORS 相关的头部信息,那么浏览器就会认为 服务器不同意预检请求
正常响应 CORS 相关字段如下:
1 | Access-Control-Allow-Methods: GET,POST,PUT // 返回服务器支持的所有请求方法 |
通过预检请求
通过预检请求后,浏览器每次发起都会带有 Origin 字段,服务器响应 也会返回相应的 Access-Control-Allow-Origin