日期:2014-05-17  浏览次数:20611 次

HTML5安全:CORS(跨域资源共享)简介

        前言:像CORS对于现代前端这么重要的技术在国内基本上居然很少有人使用和提及,在百度或者Google上搜索CORS,搜到的中文文章基本都是另外一种卫星定位技术CORS的介绍,让我等前端同学情何以堪(对比起来,用Google搜到的国外文章,基本都是跨域资源共享的介绍,说明了前端技术在国内外环境和发展的巨大差距)。

        我之前《用HTML5实现人脸识别》这篇文章中提到了“Face.com实现了CORS(跨域资源共享)。CORS系统基本上可以让服务器暴露给其它域上文件的Ajax调用。这是一个伟大的功能,我希望更多的服务能够使用它。”在这篇文章介绍的实现方式里,我们可以自由的使用自己本域的JS代码通过Ajax来调用Face.comAPI,这是一种很美妙的方式,而在以前我们很难做到这一点。

        由此我将引入和介绍CORS,希望对大家有所帮助。

定义

        CORS其实出现时间不短了,它在维基百科上的定义是:跨域资源共享(CORS )是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。而这种访问是被同源策略所禁止的。CORS系统定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。 它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。

        而W3C的官方文档目前还是工作草案,但是正在朝着W3C推荐的方向前进。

        简言之,CORS就是为了让AJAX可以实现可控的跨域访问而生的。

以往的解决方案

        以前要实现跨域访问,可以通过JSONP、Flash或者服务器中转的方式来实现,但是现在我们有了CORS。

        CORS与JSONP相比,无疑更为先进、方便和可靠。

        1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。

        2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

        3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS(这部分会在后文浏览器支持部分介绍)。

详细内容

        要使用CORS,我们需要了解前端和服务器端的使用方法。

        1、  前端

        以前我们使用Ajax,代码类似于如下的方式:

var xhr = new XMLHttpRequest();
xhr.open("GET", "/hfahe", true);
xhr.send();

        这里的“/hfahe”是本域的相对路径。

        如果我们要使用CORS,相关Ajax代码可能如下所示:

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://blog.csdn.net/hfahe", true);
xhr.send();

        请注意,代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。

        我们还必须提供浏览器回退功能检测和支持,避免浏览器不支持的情况。

function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {
    // 此时即支持CORS的情况
    // 检查XMLHttpRequest对象是否有“withCredentials”属性
    // “withCredentials”仅存在于XMLHTTPRequest2对象里
    xhr.open(method, url, true);
 
  } else if (typeof!= "undefined") {
 
    // 否则检查是否支持XDomainRequest,IE8和IE9支持
    // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式
    xhr = new XDomainRequest();
    xhr.open(method, url);
 
  } else {
 
    // 否则,浏览器不支持CORS
    xhr = null;
 
  }
  return xhr;
}
 
var xhr = createCORSRequest('GET', url);
if (!xhr) {
  throw new Error('CORS not supported');
}