跨域源资源共享CORS

CORS (Cross-Origin Resource Sharing) 定义了访问跨域资源时,浏览器与服务器如何进行沟通。
其基本思想是: 使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定 请求/响应 是成功还是失败。


当浏览器发送一个简单请求GET或POST时,会在头部附加一个Origin字段,用来说明请求页面的源信息(协议、域名、端口),以便服务器根据这个头部信息来决定是否给予响应。
若服务器认为该请求可以接受,会在Access-Control-Allow-Origin头部中回发相同的源信息(若为公共资源,则回发“*”);
若浏览器发现接收到的响应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。


【IE对CORS的实现】

IE8引入了XDR(XDomainRequest)类型,能实现安全可靠的跨域通信。
【XDR与XHR区别】:

1. cookie不在请求和响应中
2. 不能访问响应的头部信息,没办法判断status
3. 只支持GET和POST请求
4. 只能设置请求头部信息中的Content-Type字段
5. 所有XDR请求都是异步的,因此open()方法之接受两个参数:请求类型和URL
//GET
var xdr = new XDomainRequest();
xdr.onload = function(){
    console.log(xhr.responseText);
};
xdr.onerror = function(){
    console.log("发生错误");
};
xdr.open("get","url");
xdr.send(null);

为支持POST请求,XDR提供了contentType属性用来表示数据格式。

//POST
var xdr = new XDomainRequest();
xdr.onload = function(){
    console.log(xhr.responseText);
};
xdr.onerror = function(){
    console.log("发生错误");
};
xdr.open("post","url");
xdr.contentType = "application/x-www-form-urlencoded";
xdr.send("序列化的字符串");

【其他浏览器对CORS的实现】

没有XDR类型,通过XHR实现对CORS的原生支持。默认情况下,XHR对象实现的Ajax通信只能是访问同域资源。要跨域请求资源,在open()方法中传入绝对URL即可。

【跨域XHR与默认XHR区别】:

1. 不能使用setRequestHeader()设置自定义头部
2. 不能发送和接收cookie
3. 调用getAllResponseHeaders总是返回空字符串
4. 使用绝对URL
var xhr = createXHR();
xhr.readystatechange = function(){
    if(xhr.readyState == 4){
        if((xhr.status >= 200 && xhr.status < 300)||xhr.status == 304){
            console.log(xhr.responseText);
            }
        else{
            console.log("请求失败:"+xhr.status);
        }
    }
};
xhr.open("get","绝对URL",true);
xhr.send(null); 

【跨浏览器实现CORS】

function createCORSRequest(method,URL){
    var xhr = createXHR();
    if("withCredentials" in xhr){
            xhr.open(method,URL,true);
        }
        else if(typeof XDomainRequest != "undefined"){
        var xhr = new XDomainRequest();
        xhr.open(method,URL);
        }
    else{
        xhr = null;
        }
    return xhr;   
}

var request = createCORSRequest("get",URL);
if(request){
    request.onload = function(){
        //对request.responseText进行处理
    };
    request.send();
}

【Preflight Request预检请求】

浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求服务器确认允许之后,才发起实际的 HTTP 请求

【以下请求不会发起CORS预检请求】:

  • HEAD
  • GET
  • POST(Content-Type为text/plain、multipart/form-data、application/x-www-form-urlencoded)

【使用OPTIONS方法,发送下列头部】:

Origin: 发起请求的URL
Access-Control-Request-Method: 该请求的类型
Access-Control-Request-Headers: 自定义的头部信息,多个头部字段用逗号隔开

【服务器响应预检,返回下列头部】:

Access-Control-Allow-Origin: 与Origin一样
Access-Control-Allow-Methods:允许的请求方法,多种方法用逗号分隔
Access-Control-Allow-Headers: 允许的头部字段,多个头部字段用逗号分隔
Access-Control-Max-Age: 将该preflight请求缓存多少秒

默认情况下,跨域请求不提供凭据。在预检请求的返回中,服务器端可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。具体做法是将请求的withCredentials属性设置为true。若服务器接受带凭据的请求,响应中会有:

Access-Control-Allow-Credentials: true

【举个例子】:

var invocation = new XMLHttpRequest();
//要访问的跨域资源
var url = 'http://bar.other/resources/post-here/'; 
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';

function callOtherDomain(){
  if(invocation)
    {
      invocation.open('POST', url, true);
      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
      invocation.setRequestHeader('Content-Type', 'application/xml');
      invocation.onreadystatechange = handler;
      invocation.send(body); 
    }
}
//浏览器发起预检请求
OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example  //发起请求的源信息
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
//服务器返回响应
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example  //与预检请求的Origin一致
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
//预检请求完成之后,浏览器发送实际请求:
POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache
<?xml version="1.0"?><person><name>Arun</name></person>
//服务器回发响应
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some GZIP'd payload]

【参考文档】https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值