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 了。
下面是一个简单的例子
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
。
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-Method
和 Access-Control-Allow-Headers
等头部。
这里是一个简单的 DEMO 。
References