Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) 是W3C草案拟定的浏览器与服务端如何进行跨域请求的方式,其原理是用自定义HTTP头来让浏览器和SERVER决定request、response的成功或失败。目前几乎所有浏览器都已经支持了(Internet Explorer 8+, Firefox 3.5+, Safari 4+, and Chrome)。
使用一个GET或POST发送一个未自定义头的请求时,会额外添加一个叫做Origin的头,其包含了请求页面的协议、域名和端口,后台可以根据这些信息很轻松的判断出是否要给出正确的response,就像下面这样
Origin: http://www.kimhou.com
如果server允许这个请求,则会得到一个HEADER包含Access-Control-Allow-Origin的响应,而Access-Control-Allow-Origin的值则为刚刚Origin的值或*(公开资源),比如:
Access-Control-Allow-Origin: http://www.kimhou.com
如果没有这个HEADER或者HEADER不匹配,浏览器则会拒绝这个请求,匹配上了就会成功,但不管是否成功,这个请求都不会带有任何cookie信息。
之前提到的所有浏览器都支持这种简单的请求方式。Firefox 3.5+, Safari 4+和 Chrome使用XMLHttpRequest对象来实现,这跟普通的请求是一样的,但当浏览器发现请求的是跨域的资源时,CORS模式会自动被触发,而不需要额外的代码来处理:
var xhr = new XMLHttpRequest();
xhr.open("get", http://www.kimhou.com/test, true);
xhr.onload = function(){ //instead of onreadystatechange
//do something
};
xhr.send(null);
IE8中需要使用XDomainRequest
对象来实现相同的功能:
var xdr = new XDomainRequest();
xdr.open("get", http://www.kimhou.com/test);
xdr.onload = function(){
//do something
};
xdr.send();
Mozilla搞了个兼容的方法:
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get", "http://www.nczonline.net/");
if (request){
request.onload = function(){
//do something with request.responseText
};
request.send();
}
XMLHttpRequest和
XDomainRequest有着相同的属性和方法接口:
abort()
– about 进行中的请求.onerror
– 错误捕获.onload
– 请求成功.responseText
– 响应body.send()
– 发送接口.
预检请求[Preflighted requests]
CORS允许使用自定义头,用GET或POST方式和不同类型的body内容,通过服务器验证的一个透明的机制的方法称为预检请求。当你想使用预检请求时,你需要定义以下这些头信息:
Origin
– 跟上面的一样.Access-Control-Request-Method
– 请求方式.Access-Control-Request-Headers
– (Optional) 客户端使用的HEADER,用逗号隔开.
假设有一个头为NCZ的POST请求:
Origin: http://www.kimhou.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ
SERVER根据这个请求来判断并把是否允许的结果通过response的header返回给浏览器:
Access-Control-Allow-Origin
– server允许的Origin.Access-Control-Allow-Methods
– server允许的请求方式.Access-Control-Allow-Headers
– server允许的头.Access-Control-Max-Age
– 对这次预检请求的缓存时间.
比如刚刚的请求可能返回:
Access-Control-Allow-Origin: http://www.kimhou.com
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
预检请求发送后,会根据response header的max-age时间缓存起来,一般只需要一次额外的请求就可以了。
Firefox 3.5+, Safari 4+, and Chrome支持预检请求,但IE8不支持。
证书请求[Credentialed requests]
默认的跨域请求是不支持证书的,比如cookies, HTTP认证, SSL 证书等。但可以把request的withCredentials属性设置为true来实现,如果server允许证书请求则需要在返回的header中加入:
Access-Control-Allow-Credentials: true
如果server返回的header没有上面的值,浏览器不会把response返回给javascript,这里responseText得到的是空字符串,status为0,而且onerror会被触发。
而且server可能通过发送预检请求来确定是否支持证书请求。
结语
CORS技术各浏览器支持都不错,这项技术前后台只要通过很简单的改造就能实现,但现在这项技术还没有引起大家的重视,其强大的威力大家还没感受到,但相信以后会体现出来的。IE的支持力度也希望会更加给力。
参考:
http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/