CORS(跨域资源共享)

引用自阮一峰的网络日志: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的网站去请求数据

 

posted @ 2017-12-08 00:13  tatelZhang  阅读(1031)  评论(0编辑  收藏  举报