
首先,关于跨域问题,先要了解浏览器的同源策略,附上MDN的链接浏览器的同源策略,如果懒得点,我就以我的理解大概讲一哈。
浏览器同源策略的背景?
出现这个机制是为了保证用户信息安全,比如我们先浏览银行的网站,又去浏览其他的网站,如果我们的cookie包含隐私,没有限制条件的话,其他网站可以拿到用户的信息,还有一点,提交表单并不受同源政策的限制,因此才出现了这个同源的限制机制。
那么怎样才算同源与不同源
如果两个URL的协议、主机、端口都一样的话,才算是同源。这么说有点抽象,举个栗子:
URL:http://store.company.com/dir/page.html
再判断以下几个URL是否同源:
-
http://store.company.com/dir2/other.html(同源只有路径不同) -
https://store.company.com/secure.html(不同,协议不同) -
http://store.company.com:81/dir/etc.html(不同,端口号不同) -
http://news.company.com/dir/other.html(不同,主机不同)
因此,对于非同源,共有三种行为受到限制:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 无法获得
- AJAX 请求不能发送
但是呢,一些合理的用途也受到了影响,那么怎么正确处理这个问题呢?
除了架设服务器代理(也即nginx转发),有三种方法规避这个限制。
- JSONP
- Websocket
- CORS
JSONP是带有回调函数callback的json,它是一个很棒的方案,可用于解决主流浏览器的跨域数据访问的问题。但是,JSONP方案的局限性在于,JSONP只能实现GET请求。随着现在RESTful的兴起,JSONP显得力不从心了。因为,RESTful不仅有GET,还存在POST、PUT、PATCH、DELETE。
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信
CORS是跨源资源分享。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求
详解CORS
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
首先了解两种请求:简单请求和非简单请求
- 请求方法是以下三种方法之一:HEAD,GET,POST
- HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
这是为了兼容表单(form),因为历史上表单一直可以发出跨域请求。AJAX 的跨域设计就是,只要表单可以发,AJAX 就可以直接发。凡是不同时满足上面两个条件,就属于非简单请求。
对于简单请求:有几点提一下
浏览器会直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段,对于服务端而言,如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段,其中有一个Access-Control-Allow-Credentials它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。与此同时,开发者必须在AJAX请求中打开withCredentials属性。具体查一下资料就行,也就是一种协商的过程
对于非简单请求:
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

