CORS

CORS(Cross-Origin Resource Sharing),这技术的提出主要是为了解决 Ajax 的跨域问题。如果是 GET 类型的跨域请求的话,还有 JSONP 这种简单的解决方法,但像 POST 这种就复杂了,所以提出了 CORS。

XDomainRequest

IE 在 IE8 时就开始提供了跨域方案 XDomainRequest ,有了 error、timeout、progress 等处理函数,可惜得是走得太前并且当初考虑 .net 系列多导致限制有些多。

比如,对于普通的 Ajax post 来说,一般会设置 Content-Type: application/x-www-form-urlencoded,但 XDomainRequest 不能设置 header,从而只能发送纯文本,这对于服务器端会带来些困扰。PHP 在这种情况下不会把提交的键值对放进 $_POST 变量中,而需要用 HTTP_RAW_POST_DATA 来获取再解析。

也没法发送 cookie 来做身份验证。

因为限制有些多,所以 ie10 后抛弃了 XDomainRequest 而采用 XMLHttpRequest Level 2 了。

下面是一个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
function sendxDomainRequest(method, url, fn, data) {
    method = method.toUpperCase();
    var xhr = new XDomainRequest();
    xhr.open(method, url, true);
    xhr.onload = function(e) {
        fn(xhr.responseText);
    };
   
    var s = data ? data : null;
    xhr.send(s);   
}

sendxDomainRequest('POST', aCrossDomainUrl, callback, 'foo=1&bar=2');

XMLHttpRequest Level 2

CORS 的实现沿用 Ajax 的写法来获取一致性,判断是否支持 CORS 可以使用 'withCredentials' in xhrInstance

1
2
3
4
5
6
var xhr = new XMLHttpRequest();
if ('withCredentials' in xhr) {
    // next: do request
} else {
    // not support cors
}

如果不考虑判断支持的话,普通的 Ajax 请求没任何变化,但服务器端需要做些处理。发送 Ajax 时,浏览器判断到是跨域时,会添加一个名为 Origin 的头部,形如:Origin:http://example.com。这要求服务器响应时附上 Access-Control-Allow-Origin 的头部,只有当 Origin 在响应头部中时,浏览器才会认为这是一个可以通过的 CORS 请求。

Access-Control-Allow-Origin 可以是 * 这个通配符,也可以是指定的域(如 http://example.com),但不能混用(如 http://*.example.com 是不行的),也不能指定顶级域名来对应子域名(如请求头中的是 http://sub.domain.com ,返回头中的是 http://domain.com 这样也是不行的)。

所以,考虑到下面的 cookie 需要,判断出 origin ok 后,原样返回比较好。

withCredentials

默认情况下,CORS 不会携带 cookie,只有在 xhr.withCredentials = true 时才会传送待请求资源所在域的 cookie。这个时候,要求服务器端返回Access-Control-Allow-credentials: true 的头,并且 Access-Control-Allow-Origin 不能是 * ,而必须是明确的 Origin 。

上面说的都是 Simple Cross-origin Request,当需要使用到如 PUT 等方法,自定义头部等时,需要对应的返回 Access-Control-Allow-MethodAccess-Control-Allow-Headers 等头部。

这里是一个简单的 DEMO

References

  1. XDomainRequest – MSDN
  2. XDomainRequest – Restrictions, Limitations and Workarounds – MSDN Blogs
  3. XMLHttpRequest 等级 2 介绍 – 欧朋开发者社区
  4. Using CORS – html5rocks
  5. Compatibility – Can I Use
  6. CORS Spec – W3C