本文整理了一些有关跨域的基础知识和细节问题。javascript
我的一句话解释:若是 url
A
与 url
B
不一样源,那么页面A
不能获取页面B
的资源。这里有两个关键词:url
和 同源
,浏览器的同源策略就是针对两个url
,它们知足如下三个条件,才是同源:html
这里面有两个细节须要说起,域名是包括//
到/
的全部部分www.baidu.com
;没有指定端口号默认是:80
端口。跨域
若是一个页面中的JS
能够任意发起http
跨域获取其余页面上的资源,这是一件很可怕的事,举个例子:浏览器
abank.com
,服务器端验证后会在响应头中加入Set-Cookie字段,而后下次张三再发起请求,浏览器会自动将cookie附加在HTTP请求的首部字段Cookie中,服务器端就知道张三已经登陆过了。danger.com
,这个页面中写了一些Ajax
,它发起请求访问abank.com
,这一行为用户不能察觉,若是能够跨域发起请求,那么浏览器一样会自动将cookie附加在HTTP请求的首部字段Cookie中,这样这个危险危险网站就登录了张三的银行帐户。因此用同源策略来限制跨域是必须的。服务器
这里我思考了一个问题,在浏览器地址栏里输入url
为何没有出现跨域问题?
要明确,同源策略是浏览器的行为,在地址栏中输入url
是用户主观行为,因此浏览器是不判为跨域的。那么同源限制的对象实际上是页面中发起http请求的js。那同源限制的行为有哪些呢?有如下三种:cookie
接下来讲说规避跨域限制的集中方式app
JSONP利用的的是:<script>、<img>这些标签下载url中的资源是没有跨域限制的。
它的基本作法是:网页添加一个<script>元素,向服务器请求 JSON 数据,这种作法不受同源政策限制;服务器收到请求后,将JSON放在一个指定名字的回调函数里传回来。因此,顾名思义,JSONP = JSON with padding
:填充式 JSON,其实就是服务器端把 JSON 做为回调函数的参数,返回这个回调函数。cors
<script type="text/javascript"> function foo(data) { console.log('Your public IP address is: ' + data.ip); }; <script> <script type="text/javascript" src="http://example.com/ip?callback=foo"></script>
上面的script标签向服务器example.com
发出请求,该请求有一个查询字符串callback参数,用来指定回调函数的名字;服务器发现请求中有callback参数,就会将JSON做为指定回调函数的参数,回调函数做为脚本返回;脚本返回后,会直接做为代码运行,这时,只要浏览器定义了foo
函数,该函数就会当即调用。dom
JSONP的缺点在于只能发GET请求。
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS容许任何类型的请求。
CORS须要浏览器和服务器同时支持。目前,全部浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通讯过程,都是浏览器自动完成,不须要用户参与。对于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码彻底同样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感受。
所以,实现CORS通讯的关键是服务器。只要服务器实现了CORS接口,就能够跨源通讯。
阮一峰老师关于CORS的文章很是细致,跨域资源共享 CORS 详解,这里仅仅梳理下提纲备查。
浏览器将CORS请求分红两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时知足如下两大条件,就属于简单请求。
请求方法是如下三种方法之一:
HTTP的头信息不超出如下几种字段:
凡是不一样时知足上面两个条件,就属于非简单请求。
简单请求的CORS分为如下几步:
若是Origin指定的域名在服务器许可范围内,则会在报头中添加如下三个字段:
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
true
,即表示服务器明确许可,Cookie能够包含在请求中,一块儿发给服务器,另外一方面,开发者必须在AJAX请求中打开withCredentials
属性。这个值也只能设为true
,若是服务器不要浏览器发送Cookie,删除该字段便可。Access-Control-Expose-Headers
XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段。Origin
指定的域名不在服务器许可范围内,响应头中没有Access-Control-Allow-Origin
,浏览器就会抛出错误,中断这个http请求。简单请求的CORS分为如下几步:
浏览器在正式请求以前,先发送一个预检请求,预检请求的请求方法是OPTIONS
,请求头中带如下三个字段:
Access-Control-Request-Method
Access-Control-Request-Headers
若是服务器端预检不经过,浏览器报错;若是经过,返回的响应头中包含如下几个字段:
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Credentials
Access-Control-Max-Age
Origin
头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin
头信息字段。WebSocket
是一种通讯协议,使用ws://
(非加密)和wss://
(加密)做为协议前缀。该协议不实行同源政策,只要服务器支持,就能够经过它进行跨源通讯。
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。可是,两个网页一级域名相同,只是二级域名不一样,浏览器容许经过设置document.domain
共享 Cookie。
举例来讲,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要在两个网页的脚本中设置的document.domain='example.com',两个网页就能够共享Cookie。
若是两个网页不一样源,就没法拿到对方的DOM。典型的例子是iframe
窗口和window.open
方法打开的窗口,它们与父窗口没法通讯。对于彻底不一样源的网站,目前有三种方法,能够解决跨域窗口的通讯问题:
window.postMessage