在公众号中陆陆续续有看到一些讲前端跨域的文章,自己工作中也用到了一些。印象中的跨域方法有很多种,但一直记不全,索性将之前收藏的文章再过一遍,自己做个总结,以后就不用辛苦翻看那些零散的文档了。🙄🙄🙄
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传递数据。