引用自阮一峰的网络日志:http://www.ruanyifeng.com/blog/2016/04/cors.html 侵删
一、浏览器将CORS请求(通过ajax方式)分成两类:
1.简单请求:需要同时满足以下两大条件
1).请求方法为:HEAD、GET、POST之一
2).HTTP的请求头信息不超出以下字段:Accept、Accept-Language、Content-Language、Last-Event-ID、
Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
2.非简单请求:凡是不同时满足上面两个条件的都属于非简单请求
二、简单请求
浏览器直接发出CORS请求,在头信息中添加一个Origin字段:
// 该站点发送的ajax请求
GET /x/web-interface/online HTTP/1.1 Host: api.bilibili.com Connection: keep-alive Accept: */* Origin: https://bangumi.bilibili.com User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 Referer: https://bangumi.bilibili.com/anime/5978/play Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.8
通过Origin字段说明本次请求来自哪个源,服务器根据这个值,决定是否同意这次请求
// 正常的响应头
HTTP/1.1 200 OK Date: Thu, 07 Dec 2017 14:33:56 GMT Content-Type: application/json;charset=utf-8 Content-Length: 269 Connection: keep-alive Access-Control-Allow-Origin: https://bangumi.bilibili.com Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires,Content-Type,Access-Control-Allow-Credentials X-Cache: BYPASS from cn-sccd2-cmcc-w-02.hdslb.com
响应头中与CORS请求相关字段
Access-Control-Allow-Origin: 必须的字段;要求值是请求的Origin的值;或者为*,表示可任意跨域
Access-Control-Allow-Credentials:可选的字段;布尔值(默认无该字段);表示是否允许发送cookie,默认情况下cookie不包括在CORS请求中;
若设置为true表示服务器明确许可,cookie可以包含在请求中一同发送给服务器
Access-Control-Allow-Headers
Access-Control-Expose-Headers:可选字段;CORS请求时,XHR对象的getResponseHeader() 方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma;
如果想要拿到其他字段,就需要在这个字段中指定
如果Origin指定的源不在许可范围,服务器也会返回一个正常的HTTP回应,但是浏览器会发现响应头中没有包含
指定字段: Access-Control-Allow-Origin字段,或者与请求头中的Origin不匹配,就会知道出错了
// 通过本地服务器向 发送http://www.bilibili.com/x/web-interface/online ajax请求的请求头
Accept:*/* Accept-Encoding:gzip, deflate Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Host:api.bilibili.com Origin:http://127.0.0.1:7824 Referer:http://127.0.0.1:7824/hello.html User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
// 通过本地文件 发送http://www.bilibili.com/x/web-interface/online ajax请求的请求头
Accept:*/* Accept-Encoding:gzip, deflate Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Host:api.bilibili.com Origin:null User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
//服务器可以进行响应; 但是因为请求头的Origin和响应头Access-Control-Allow-Origin: https://bangumi.bilibili.com(或响应头无该字段) 不相符,浏览会进行报错;不会处理结果
HTTP/1.1 200 OK Date: Thu, 07 Dec 2017 15:19:21 GMT Content-Type: application/json;charset=utf-8 Content-Length: 269 Connection: keep-alive X-Cache: BYPASS from cn-sccd2-cmcc-w-01.hdslb.com
三、非简单请求
非简单请求是一种 对服务器有特殊要求的请求;比如说PUT或DELETE等请求,或者Content-Type字段类型为application/json
非简单请求会在正是通信之前,增加一次HTTP查询请求(预检preflight)
询问服务器当前域名是否在服务器许可名单当中,以及可以使用的哪些HTTP动词和字段;只有得到肯定答复,浏览器才会正是的发出ajax请求,否则报错;
// put 请求
var url = 'http://api.alice.com/cors'; var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); // 自定义头 xhr.send();
预检请求头
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
预检请求的方法是 OPTIONS;表示这个请求是用来询问的,头信息中关键字Origin表示来源
请求头字段
1.Access-Control-Request-Method:表示CORS请求会用到哪些HTTP方法
2.Access-Control-Request-Headers:指定浏览器CORS请求会发送的头信息字段
预检响应
服务器确认允许跨域请求时,就可以做出回应
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
如果浏览器否定预检请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段,浏览器会认定浏览器不太同意预检请求,会触发一个错误
响应头字段
1.Access-Control-Allow-Methods:必须字段;逗号分隔字符串;表明服务器支持的所有跨域请求的方法;避免多次预检请求
2.Access-Control-Allow-Headers:如果请求中包含Access-Control-Request-Headers字段,该字段为必须字段
3.Access-Control-Allow-Credentials:同简单请求
4.Access-Control-Max-Age:可选字段;指定预检有效期
通过预检请求后,以后每次浏览器的CORS请求就和简单请求一样会有一个Origin头信息字段
//本地非简单请求
// 本地服务器非简单请求结果
// 该站点非简单请求
CORS与JSONP都是用于跨域的,但是更为强大,支持所有类型的HTTP请求;
而JSONP的优势在于支持老式浏览器,以及向不支持CORS的网站去请求数据