使用CORS来进行跨域AJax请求

来源:互联网 发布:淘宝卖家遭遇诈骗 编辑:程序博客网 时间:2024/06/08 01:33
     以前出于安全考虑,javascript的Ajax请求都必须是同域下的,为了解决跨域请求大家无所不用其极,什么jsonp, 代理都是大家常用的方法,跨域需求这么大,于是现在还是搞了个CORS的跨域技术了。


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/

原创粉丝点击