首先,什么是跨域?
跨域问题来自于浏览器的同源策略。由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。
然而在现如今的开发中,跨域获取资源已经变得非常常见。
目前主流的几种跨域解决方案有:
JSPON
CORS
proxy
....
这之中,JSPON是从前我们常用的跨域策略。但JSPON有一个缺点,就是只支持get请求,当要传输的数据量比较大而必须使用post请求方式的时候,JSPON就不灵了
CORS是w3c为了解决浏览器跨域请求而制定的标准草案。
CORS旨在定义一种规范,让浏览器从提供者处获取资源时能够正确的判定是否将该资源分发给客户端做进一步处理。CORS利用资源提供者的显示授权来决定目标资源是否与消费者共享。
CORS原理:
支持CORS的浏览器在发送请求的时候会携带一个名为Origin的报头来表明发起请求的页面所在的站点,服务器接收到请求后会根据该Origin报头来判断是否将资源分配给该站点。
资源提供者的允许授权通过响应报头“Access-Control-Allow-Origin”来承载。其报头的值表示得到授权的站点。若“Access-Control-Allow-Origin”的值为*,则表示该资源是公开的,任何站点都可以获取。
这些授权都需要资源提供服务器方来设置。若站点没有授权,则可以将该值设置为null,或者让响应报头不具有该报头。
服务器获得响应报头后会提取该报头的值,若其中包含的授权站点列表中存在Origin或值为*,则表示Origin站点有权限获取该资源;若响应头中不存在“Access-Control-Allow-Origin”报头或其值为null,客户端对该资源的javascript操作会被拒绝。
预检测机制:
w3c的cros标准将跨域资源请求分为两种类型:简单请求和非简单请求
简单请求:
请求采用简单http方法,并且自定义请求报头为空,或者所有自定义请求报头均为简单请求报头。
简单http 方法:get、post、head
请求报头分为两种:
一种是浏览器自动生成的报头,一种是通过javascript添加的报头,称为自定义报头。
简单请求报头:
Accept
Accept-Language
Content-Language
3种类型的Content-Type:
1.application/x-www-form-urlencode
2.multipart/form-data
3.text-plain
由于简单请求不是以更新服务器资源为目的的,服务器对请求对处理不会导致自身维护资源的改变。因此,对于简单跨域请求,浏览器把取得权限和获取资源两个步骤合二为一。
如果请求涉及到对资源的改变,CORS规定浏览器应采用预检测机制(preflight)来处理这类非简单请求。
资源提供者在收到预检测请求后,根据其提供的相关报头进行授权检测。检测逻辑包括:
1.请求站点是否可信
2.采用的HTTP方法是否被允许
3.自定义报头是否被允许
预检测通过,返回200,OK 授权信息会包含在响应报头中;若预检测没有通过授权检验,返回400,Bad Request。
预检测请求:
该请求采用HTTP-OPTIONS方法,是一个不包含body的请求,同时用户凭证的光管报头也会被剔除。
包含的请求报头--
代表请求页面所在的站点:Origin
典型的请求报头:
Access-Control-Request-Method 真正的跨域资源请求采用的http方法
Access-Control-Request-Headers 真正跨域资源请求携带的自定义报头列表
典型的响应头:
Access-Control-Allow-Origin 允许跨域资源请求的站点列表
Access-Control-Expose-Headers 直接暴露给客户端JavaScript程序的响应报头
Access-Control-Allow-Methods 跨域资源请求允许使用的HTTP方法列表
Access-Control-Allow-Headers 跨域资源请求允许携带的自定义报头列表
Access-Control-Max-Age 浏览器可以将响应结构缓存的时间(/s),避免浏览器频繁发送预检测请求
浏览器在接收预检测响应后,会根据响应头确定后续发送的真正的跨域资源请求是否会被接受。具体检验逻辑如下:
1.Origin代表的请求站点须存在于Access-Control-Allow-Origin响应头表示的站点列表中
2.响应报头Accell-Control-Allow-Methods不存在或Access-Control-Request-Method标示的请求方法在响应报头的请求方法列表中
3.Access-Control-Request-Headers中的请求头均在Access-Control-Allow-Headers的报头列表中
只有在确定服务端一定会接受的情况下,浏览器才会发送真正跨域资源请求。预检响应结果会被浏览器缓存,在“Access-Control-Max-Age”报头设定的时间内,缓存的结果将被浏览器用户进行授权检验,所以在此期间不会再有预检请求发送。
关于用户凭证:
ajax请求默认不发送用户凭证,若需要用户凭证附加到Ajax请求上,需要将XMLHttpReuqest的withCredentials 属性设置为True,并且在服务端显示声明支持用户凭证,否则请求会被拒绝。在W3C的CORS规范来说,服务端利用响应报头“Access-Control-Allow-Credentials”来表明自身是否支持用户凭证。
CORS跨域主要需要服务端做相应配置,客户端不需要特殊处理,正常发送ajax请求即可。