CORS正确使用姿势
2017-02-25 20:36
183 查看
CORS用法
首先要知道的是对于CORS,我们要用到XHR2,然后IE的话是XDomainRequest Object,它从IE10开始才是XHR2. IE 8 9都是XDomainRequest首先需要写一个处理兼容性的函数,确定是哪个浏览器上运行
function createCORSRequest(method,url){ var xhr=new XMLHttpRequest(); if("withCredentials" in xhr) { //Check if the XMLHttpRequest object has a "withCredentials" property //this property only exists on XHR 2 object }else if(typeof XDomainRequest!='undefined'){ //otherwise check if XDomainRequest //XDomainRequest only exists in IE xhr =new XDomainRequest(); xhr.open(method,url); }else{ //othewise CORS is not supported by the browser xhr=null; } return xhr; }
该函数先检测XHR对象是否有withCredentials属性,这个属性只有XHR2的对象才有。
然后检测XDomainRequest是否存在。
实际的请求处理代码
function makeCORSRequest(){ // var url=''; var xhr=createCORSRequest('GET',url); if(!xhr){ throw new Error('CORS not supported'); return ; } //Reponse Handlers xhr.onload=function(){ var text=xhr.responseText; var title=getTitle(text); console.log('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror=function(){ alert('Woops, there was an error making the request.'); }; xhr.send(); //send(data) }
我们做了一个简单的GET请求,如果xhr不存在,即这是个不支持CORS的浏览器,就抛出这个错误并返回。
然后在onload(成功请求并返回)的事件中处理我们的业务,在onerror里面是处理请求过程出错的业务。
注意
浏览器对于出错的report不是做的很好,比如FF仅仅report status 0 和一个空的statusText for all errors! 浏览器可能会console.log输出信息,但是这些信息不能被js访问到!!! 所以handle onerror你仅仅是知道出错了。
XHR2新增的事件及其含义
Event Handler | Description |
---|---|
onloadstart | 请求开始的时候 |
onprogress | 当前正在加载读取数据中 |
onerror | 请求失败 |
onload | 请求成功完成 |
ontimeout | 在请求完成之前超时了 |
添加CORS支持到服务器
在CORS中,当我们处理浏览器和服务器浏览器时,浏览器会添加一些额外的headers,还可能做一些额外的请求(浏览器自动发出)我们可以通过抓包工具(例如fiddle)看到这些被隐藏起来的请求。
可以看到浏览器发送了preflight request
CORS请求类型
简单请求和非简单请求简单请求就是
- HEAD
- GET
- POST
HTTP Headers 匹配下面的
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type, 但值是其中的一种:
application/x-www-form-urlencoded
multipart/form-data
text/plain
简单的请求我们只需要用JSON-P或者HTML 表单post来请求即可,不需要用到CORS。
处理CORS和同源的原理
注意的是一个有效的CORS请求,总是包含了一个“Origin” header,这是被浏览器自动附加的,但是这个并不是表明这个请求一定是跨域请求。 一些浏览器的同源请求也会有这个header。一个HTTP 请求例子:
POST /cors HTTP/1.1 Origin:http://api.bob.com Host: api.bob.com
不过浏览器会expect CORS的响应头,如果是跨域的情况下,同源的时候,它不会理会是否有CORS 的headers。
一个有效的服务器CORS响应:
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
详解介绍这些响应的意义
Access-Control-Allow-Origin(required)这个header必须included,所有有效的CORS响应都必须要有。 它的值可以设置成特定的origin 或者 是 “*”,一般也就是你请求脚本所在的源。
Access-Control-Allow-Credentials(optional)
默认,cookie是不会在CORS请求中被附加的,使用这个头,设置成true表示客户端可以附加cookie到CORS请求。 如果你不需要cookie就不用设置。
不要设置成false!!!!
如果在你的JS中设置了XHR 2 对象的widthCredentials属性,这个属性也都必须设置成true才能成功。
两个都必须有
另外附加说明:
这些跨域设置的cookie,也遵循同源策略,你的JS不能通过document.cookies or response headers访问这些cookies
只能被remote domain (即远端服务器)所控制。
Access-Control-Expose-Headers (optional)
XHR2 对象有一个getResponseHeader()方法,返回特定的响应头。 当一个CORS请求时,getResponseHeader()方法默认只能访问下面这些简单的响应头:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
如果你要访问其他header,就要用这个Access-Control-Expose-Headers
如果一个不那么简单的请求,实际包括两个请求
一个preflight request和一个actual requestJS代码
var url = 'http://api.alice.com/cors'; var xhr = createCORSRequest('PUT', url); xhr.setRequestHeader( 'X-Custom-Header', 'value'); xhr.send();
HTTP请求响应如下
Preflight Reqeust Header
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...
Preflight Response Header
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
preflight请求是一个HTTP OPTIONS 请求,你的服务器要能够响应这种method。
它也包含了一些专有的request heaer
Access-Control-Request-Method指定实际请求的HTTP method,这个一定要有。
Access-Control-Request-Headers
Preflight Request的作用
发送HTTP OPTIONS方法试探真实请求是否能够安全发送,询问是否允许真实请求(actual request)。服务端会根据两个headers来验证HTTP method和真实请求的method是否有效。对于Preflight response
有以下的response header:Access-Control-Allow-Origin
同样是必须提供的
Access-Control-Allow-Methods
允许的HTTP 方法,这个响应头可以包含服务器支持的所有HTTP方法。 因为preflight response可能被cached缓存,所以一个简单preflight response可以包含很多细节关于多种请求类型。
Access-Control-Allow-Headers
如果请求有一个 Access-Control-Request-Headers header的header就需要这个响应头~
可以返回所有服务器支持的响应头。
Access-Control-Max-Age
这个响应头可以使得每个preflight请求变得昂贵。
因为浏览器时做了两个请求weighted每个客户端请求。这个响应头可以让响应被缓存(cached)一个特定的时间。
我们来看真实(实际)请求
请求体PUT /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com X-Custom-Header: value Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
响应体
Access-Control-Allow-Origin: http://api.bob.com Content-Type: text/html; charset=utf-8
我们可以看到真实请求中,我们的方法是put,而响应少了很多header,因为前面的preflight响应过了。
服务器如何拒绝
如果服务器要拒绝CORS请求,直接返回一个没有CORS header的普通响应即可。有时服务器想要拒绝请求如果在preflight请求中的HTTP method 或者首部(headers)是无效的。
浏览器接收到响应之后,发现没有CORS的headers,就不会做一个真实(实际)的请求。
兼容性
Chrome 3+Firefox 3.5+
Opera 12+
Safari 4+
Internet Explorer 8+
相关文章推荐
- 使用Flume Log4j Appender正确的姿势
- 新手与大神就在一念之间,论HTML5的正确使用姿势。创优翼教育
- 【Python环境】如何使用正确的姿势进行高效Python函数式编程?
- 使用开源项目的正确姿势,都是血和泪的总结!
- 使用开源项目的正确姿势,都是血和泪的总结!
- 使用Flume Log4j Appender正确的姿势
- MongoDB Driver:使用正确的姿势连接复制集
- 如何使用Elastic Search正确的姿势进行搜索
- 使用libcurl的正确姿势
- 单例模式的正确使用姿势
- Fragment使用的正确姿势
- 玩转渗透神器Kali:Kali Linux作为主系统使用的正确姿势TIPS
- 使用正确的姿势更新SSIS Data Flow Component以适应字段类型变化
- 玩转***神器Kali:Kali Linux作为主系统使用的正确姿势TIPS
- FlowDroid在Ubuntu上正确使用姿势
- 容器中使用erase的正确姿势(List Iterator Not Incrementable)
- 使用libcurl的正确姿势
- Windows 10 代理上网用户的正确使用姿势
- 用正确的姿势使用volley
- datasheet 使用的正确姿势