CORS正确使用姿势

CORS用法

首先要知道的是对于CORS,我们要用到XHR2,然后IE的话是XDomainRequest Object,它从IE10开始才是XHR2. IE 8 9都是XDomainRequest

首先需要写一个处理兼容性的函数,确定是哪个浏览器上运行

function createCORSRequest(method,url){
    var xhr=new XMLHttpRequest();
    if("withCredentials" in xhr)    {
        //Check if the XMLHttpRequest object has a "withCredentials" property
        //this property only exists on XHR 2 object

    }else if(typeof XDomainRequest!='undefined'){
        //otherwise check if XDomainRequest
        //XDomainRequest only exists in IE 
        xhr =new XDomainRequest();
        xhr.open(method,url); 
    }else{
        //othewise CORS is not supported by the browser
        xhr=null;
    }
    return xhr;
}

该函数先检测XHR对象是否有withCredentials属性,这个属性只有XHR2的对象才有。
然后检测XDomainRequest是否存在。

实际的请求处理代码

function makeCORSRequest(){
    //
    var url='';
    var xhr=createCORSRequest('GET',url);
    if(!xhr){
        throw new Error('CORS not supported');
        return ;
    }
    //Reponse Handlers
    xhr.onload=function(){
        var text=xhr.responseText;
        var title=getTitle(text);
        console.log('Response from CORS request to ' + url + ': ' + title);
    };

    xhr.onerror=function(){
        alert('Woops, there was an error making the request.');
    };

    xhr.send(); //send(data)
}

我们做了一个简单的GET请求,如果xhr不存在,即这是个不支持CORS的浏览器,就抛出这个错误并返回。
然后在onload(成功请求并返回)的事件中处理我们的业务,在onerror里面是处理请求过程出错的业务。

注意
浏览器对于出错的report不是做的很好,比如FF仅仅report status 0 和一个空的statusText for all errors! 浏览器可能会console.log输出信息,但是这些信息不能被js访问到!!! 所以handle onerror你仅仅是知道出错了。

XHR2新增的事件及其含义

Event HandlerDescription
onloadstart请求开始的时候
onprogress当前正在加载读取数据中
onerror请求失败
onload请求成功完成
ontimeout在请求完成之前超时了

注意:XHR以前只有一个onreadystatechange事件

添加CORS支持到服务器

在CORS中,当我们处理浏览器和服务器浏览器时,浏览器会添加一些额外的headers,还可能做一些额外的请求(浏览器自动发出)
我们可以通过抓包工具(例如fiddle)看到这些被隐藏起来的请求。
这里写图片描述

可以看到浏览器发送了preflight request

CORS请求类型

简单请求和非简单请求
简单请求就是
- HEAD
- GET
- POST

HTTP Headers 匹配下面的

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type, 但值是其中的一种:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

简单的请求我们只需要用JSON-P或者HTML 表单post来请求即可,不需要用到CORS。

处理CORS和同源的原理

注意的是一个有效的CORS请求,总是包含了一个“Origin” header,这是被浏览器自动附加的,但是这个并不是表明这个请求一定是跨域请求。 一些浏览器的同源请求也会有这个header。

一个HTTP 请求例子:

POST /cors HTTP/1.1
Origin:http://api.bob.com
Host: api.bob.com

不过浏览器会expect CORS的响应头,如果是跨域的情况下,同源的时候,它不会理会是否有CORS 的headers。

一个有效的服务器CORS响应:

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

详解介绍这些响应的意义

Access-Control-Allow-Origin(required)
这个header必须included,所有有效的CORS响应都必须要有。 它的值可以设置成特定的origin 或者 是 “*”,一般也就是你请求脚本所在的源。

Access-Control-Allow-Credentials(optional)
默认,cookie是不会在CORS请求中被附加的,使用这个头,设置成true表示客户端可以附加cookie到CORS请求。 如果你不需要cookie就不用设置。
不要设置成false!!!!
如果在你的JS中设置了XHR 2 对象的widthCredentials属性,这个属性也都必须设置成true才能成功。
两个都必须有

另外附加说明:
这些跨域设置的cookie,也遵循同源策略,你的JS不能通过document.cookies or response headers访问这些cookies
只能被remote domain (即远端服务器)所控制。

Access-Control-Expose-Headers (optional)
XHR2 对象有一个getResponseHeader()方法,返回特定的响应头。 当一个CORS请求时,getResponseHeader()方法默认只能访问下面这些简单的响应头:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

    如果你要访问其他header,就要用这个Access-Control-Expose-Headers

如果一个不那么简单的请求,实际包括两个请求

一个preflight request和一个actual request
JS代码

var url = 'http://api.alice.com/cors';
var xhr = createCORSRequest('PUT', url);
xhr.setRequestHeader(
    'X-Custom-Header', 'value');
xhr.send();

HTTP请求响应如下

这里写图片描述

Preflight Reqeust Header

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

Preflight Response Header

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8

preflight请求是一个HTTP OPTIONS 请求,你的服务器要能够响应这种method。

它也包含了一些专有的request heaer

Access-Control-Request-Method
指定实际请求的HTTP method,这个一定要有。

Access-Control-Request-Headers

Preflight Request的作用

发送HTTP OPTIONS方法试探真实请求是否能够安全发送,询问是否允许真实请求(actual request)。服务端会根据两个headers来验证HTTP method和真实请求的method是否有效。

对于Preflight response

有以下的response header:
Access-Control-Allow-Origin
同样是必须提供的
Access-Control-Allow-Methods
允许的HTTP 方法,这个响应头可以包含服务器支持的所有HTTP方法。 因为preflight response可能被cached缓存,所以一个简单preflight response可以包含很多细节关于多种请求类型。

Access-Control-Allow-Headers
如果请求有一个 Access-Control-Request-Headers header的header就需要这个响应头~
可以返回所有服务器支持的响应头。
Access-Control-Max-Age
这个响应头可以使得每个preflight请求变得昂贵。
因为浏览器时做了两个请求weighted每个客户端请求。这个响应头可以让响应被缓存(cached)一个特定的时间。

我们来看真实(实际)请求

请求体

PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

响应体

Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

我们可以看到真实请求中,我们的方法是put,而响应少了很多header,因为前面的preflight响应过了。

服务器如何拒绝

如果服务器要拒绝CORS请求,直接返回一个没有CORS header的普通响应即可。
有时服务器想要拒绝请求如果在preflight请求中的HTTP method 或者首部(headers)是无效的。
浏览器接收到响应之后,发现没有CORS的headers,就不会做一个真实(实际)的请求。

兼容性

Chrome 3+
Firefox 3.5+
Opera 12+
Safari 4+
Internet Explorer 8+

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CORS (跨域资源共享) 是一种在浏览器中解决跨域问题的机制。当一个页面通过 AJAX 请求去访问另一个源(域、协议、端口不同),浏览器会发送一个跨域请求。 CORS使用需要在服务端和客户端两个方面进行设置。在服务端,需要在响应头中添加一些信息来允许跨域请求。常见的响应头字段包括 "Access-Control-Allow-Origin"、"Access-Control-Allow-Methods"、"Access-Control-Allow-Headers"等。通过设置这些字段,服务器可以指定允许的跨域客户端。比如,使用 \* 可以允许所有跨域请求。 在客户端,可以使用 JavaScript 进行 CORS 的处理。一般情况下,浏览器会发送一个 OPTIONS 请求进行预检(preflight)以确定是否允许发送跨域请求。在实际发送跨域请求之前,浏览器会发送一个带有特殊的头部信息的 OPTIONS 请求。如果服务器设置了合适的响应头,浏览器会发送正式的请求获取所需的资源。 可以使用 JavaScript 的 XMLHTTPRequest 或者 Fetch API 发起跨域请求并处理响应。当然,如果需要在跨域请求中携带身份凭证,需要将 withCredentials 属性设置为 true。 使用 CORS 可以实现跨域请求,但需要注意安全性问题。如果服务器没有正确设置响应头,可能会导致安全漏洞。因此,在使用 CORS 时需要确保服务器端的设置是安全可靠的。 总之,CORS 是一种解决跨域问题的机制,通过在服务端和客户端进行设置,可以实现安全可靠的跨域请求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值