在公众号中陆陆续续有看到一些讲前端跨域的文章,自己工作中也用到了一些。印象中的跨域方法有很多种,但一直记不全,索性将之前收藏的文章再过一遍,自己做个总结,以后就不用辛苦翻看那些零散的文档了。🙄🙄🙄
JSONP
适用范围
前端向跨域后端接口请求数据。
缺陷
- 它没有关于
JSONP
调用的错误处理,一旦回调函数调用失败,浏览器会以静默失败的方式处理。 - 它只支持
GET
请求,这是由于该技术本身的特性所决定的。因此,对于一些需要对安全性有要求的跨域请求,JSONP
的使用需要谨慎一点了。
优点
由于JSONP
对于老浏览器兼容性方面比较良好,因此,对于那些对IE8
以下仍然需要支持的网站来说,仍然被广泛应用。
原理
通过script
标签引入的js
是不受同源策略的限制的。所以我们可以通过script
标签引入一个js
或者是一个其他后缀形式(如php
等)的文件,此文件返回一个js
函数的调用。JSONP
正是利用这个特性来实现的。
示范
详细细节参考【1】,大致如下:
前端
1 | <script type="text/javascript"> |
后端
1 | $callback = $_GET['callback'];//得到回调函数名 |
或者利用 jquery 封装的方法
1 | <script type="text/javascript"> |
document.domain
适用范围
两个前端页面拥有共同的主域,但子域不同,可自由相互通信。
推荐一个使用 iframe 跨域的库https://github.com/jpillora/xdomain
。
示范
详细细节参考【1】,大致如下:
把http://www.example.com/a.html
和 http://example.com/b.html
这两个页面的document.domain
都设成相同的域名就可以了。
但要注意的是,document.domain
的设置是有限制的,我们只能把document.domain
设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com
中某个文档的document.domain
可以设成a.b.example.com
、b.example.com
、example.com
中的任意一个,但是不可以设成 c.a.b.example.com
,因为这是当前域的子域,也不可以设成baidu.com
,因为主域已经不相同了。
window.name
适用范围
两个前端页面完全跨域,更多用于单向通信
原理
window
对象有个name
属性,该属性有个特征:即在一个窗口(window
)的生命周期内,窗口载入的所有的页面都是共享一个window.name
的,每个页面对window.name
都有读写的权限,window.name
是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
示范
详细细节参考【1】。
其中 A 页面若想和跨域的 B 页面通信,可以在 A 下利用一个iframe
先加载 B,往window.name
中设置数据,再利用此iframe
转到与 A 同域的任一页面,此时 A 就能直接从iframe
的window.name
中拿数据了。
iframe
+location.hash
适用范围
两个前端页面完全跨域,可自由相互通信。
原理
与上面介绍的window.name
有一点类似,只不过一个是修改name
,一个是修改url hash
。
监听hash
变化可以使用onhashchange
事件,在不支持的浏览器上通过只能通过定时器轮询。
缺点
- 在改变
hash
时还会增加浏览器历史记录。 - 数据直接暴露在了
url
中,数据容量和类型都有限等。
示范
此方法用的比较少,详细细节参照【2】
window.postMessage
适用范围
两个前端页面完全跨域,可自由相互通信。此为HTML5
的 API,具体使用可以参见MDN
,在此不详述。
反向代理
主要是利用http
服务器例如nginx
的反向代理配置来转发请求。例如:
1 | { |
CORS
适用范围
与JSONP
类似,前端向跨域后端接口请求数据。
优点
- 除了
GET
方法外,也支持其它的HTTP
请求方法如POST
、PUT
等。 - 可以使用
XHR
进行传输,所以它的错误处理方式比JSONP
好。
原理
通过一系列新增的HTTP
头信息来实现服务器和客户端之间的通信。所以,要支持CORS
,服务端需要做好相应的配置。具体细节参见【5】
其他
WebSocket
协议跨域【3】
【4】中介绍了一种在两个完全不相干的浏览器跨域 tab 页之间进行通信的技巧,核心思想是这两个 tab 页都嵌入一个iframe
,两个iframe
加载两个同域的页面。 tab 页和iframe
之间的通信可以使用上面说的方法(例如postMessage
),两个iframe
之间因为是同域的,可以使用localStorage
传递数据。