跨站资源共享(CORS)

跨域http请求

当两个站点的协议(http、https、ftp)、域名、端口不同时,该两个站点构成跨域。出于安全原因, 浏览器会限制脚本发起跨域http请求(也有可能是正常发送,但是拦截返回值)。实际项目中常用的解决跨域的方法通常有JSONP、CORS等。

使用CORS跨域

JSONP跨域比较简单,不需要服务器端配合,但是只能发送GET请求;CORS是目前使用最为广泛的跨域解决方案,需要服务端的配合。

简单请求与非简单请求

浏览器将CORS分为简单请求和非简单请求,非简单请求需要首先发送CORS预检请求,相当于发送两次请求,当预检请求成功后,才发送真正的http请求.

简单请求

若请求满足所有下述条件,则该请求可视为“简单请求”

  • 使用下列方法:

    1. GET
    2. POST
    3. HEAD
  • http的首部仅能包含以下:

    1. Accept
    2. Accept-Language
    3. Content-Language
    4. Content-Type (text/plain、multipart/form-data、application/x-www-form-urlencoded)
    5. DPR
    6. Downlink
    7. Save-Data
    8. Viewport-Width
    9. Width

客户端和服务器之间使用 CORS 首部字段来处理跨域权限:
这里写图片描述

请求头部:
    GET /resources/public-data/ 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
    Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
    Origin: http://foo.example

响应头部:
    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 00:23:53 GMT
    Server: Apache/2.0.61 
    Access-Control-Allow-Origin: *
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: application/xml

    [XML Data]
> 请求头部中的Origin字段表示请求来源这个域,与响应头部中的Access-Control-Allow-Origin字段形成简单访问控制。
非简单请求

非简单请求需要首先发送预检请求,预检请求就是使用options方法(http的一种方法),发起一个预检请求到服务器,确认服务器是否该实际请求;如果服务器否定了“预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。

当请求满足下述任一条件时,即应首先发送预检请求:
使用下列方法:
1. PUT
2. DELETE
3. CONNECT
4. OPTIONS
5. TRACE
6. PATCH

http的首部仅能包含以下:
1. Accept
2. Accept-Language
3. Content-Language
4. Content-Type (不为text/plain、multipart/form-data、application/x-www-form-urlencoded)
5. DPR
6. Downlink
7. Save-Data
8. Viewport-Width
9. Width

如下是一个需要执行预检请求的 HTTP 请求:

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); 
    }
}

上述代码中,使用了自定义的http头信息“X-PINGOTHER”,而且Content-Type为application/xml,所以需要发送预检请求。

这里写图片描述

首先通过options方法发送预检请求,预检请求验证通过后发送真正的请求,最后完成http请求。

附带身份凭证的请求

CORS可以基于HTTP cookies和HTTP发送身份凭证,一般对于跨域的XMLHttpRequest请求,浏览器不会发送身份凭证信息,如果需要发送则需要设置标志位(withCredentials = true)

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';

function callOtherDomain(){
  if(invocation) {
    invocation.open('GET', url, true);
    invocation.withCredentials = true; //向服务器发送cookies
    invocation.onreadystatechange = handler;
    invocation.send(); 
  }
}

如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

这里写图片描述

参考文献
[1]: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、付费专栏及课程。

余额充值