前端跨域方法小结

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

JSONP

适用范围

前端向跨域后端接口请求数据。

缺陷

  1. 它没有关于JSONP调用的错误处理,一旦回调函数调用失败,浏览器会以静默失败的方式处理。
  2. 它只支持GET请求,这是由于该技术本身的特性所决定的。因此,对于一些需要对安全性有要求的跨域请求,JSONP的使用需要谨慎一点了。

优点

由于JSONP对于老浏览器兼容性方面比较良好,因此,对于那些对IE8以下仍然需要支持的网站来说,仍然被广泛应用。

原理

通过script标签引入的js是不受同源策略的限制的。所以我们可以通过script标签引入一个js或者是一个其他后缀形式(如php等)的文件,此文件返回一个js函数的调用。JSONP正是利用这个特性来实现的。

示范

详细细节参考【1】,大致如下:

前端

1
2
3
4
5
6
<script type="text/javascript">
function dosomething(jsondata) {
//处理获得的json数据
}
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>

后端

1
2
3
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出

或者利用 jquery 封装的方法

1
2
3
4
5
<script type="text/javascript">
$.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){
    //处理获得的json数据
});
</script>

document.domain

适用范围

两个前端页面拥有共同的主域,但子域不同,可自由相互通信。

推荐一个使用 iframe 跨域的库https://github.com/jpillora/xdomain

示范

详细细节参考【1】,大致如下:

http://www.example.com/a.htmlhttp://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。

但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 可以设成a.b.example.comb.example.comexample.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 就能直接从iframewindow.name中拿数据了。

iframe+location.hash

适用范围

两个前端页面完全跨域,可自由相互通信。

原理

与上面介绍的window.name有一点类似,只不过一个是修改name,一个是修改url hash

监听hash变化可以使用onhashchange事件,在不支持的浏览器上通过只能通过定时器轮询。

缺点

  1. 在改变hash时还会增加浏览器历史记录。
  2. 数据直接暴露在了url中,数据容量和类型都有限等。

示范

此方法用的比较少,详细细节参照【2】

window.postMessage

适用范围

两个前端页面完全跨域,可自由相互通信。此为HTML5的 API,具体使用可以参见MDN,在此不详述。

反向代理

主要是利用http服务器例如nginx的反向代理配置来转发请求。例如:

1
2
3
4
5
6
7
8
9
{
"/test-nginx": {
"target": "http://localhost:3000",
"secure": false,
"pathRewrite": {
"^/test-nginx": ""
}
}
}

CORS

适用范围

JSONP类似,前端向跨域后端接口请求数据。

优点

  1. 除了 GET 方法外,也支持其它的 HTTP 请求方法如 POSTPUT 等。
  2. 可以使用 XHR进行传输,所以它的错误处理方式比 JSONP 好。

原理

通过一系列新增的HTTP头信息来实现服务器和客户端之间的通信。所以,要支持CORS,服务端需要做好相应的配置。具体细节参见【5】

其他

  • WebSocket协议跨域【3】

【4】中介绍了一种在两个完全不相干的浏览器跨域 tab 页之间进行通信的技巧,核心思想是这两个 tab 页都嵌入一个iframe,两个iframe加载两个同域的页面。 tab 页和iframe之间的通信可以使用上面说的方法(例如postMessage),两个iframe之间因为是同域的,可以使用localStorage传递数据。

参考

  1. JS 中几种实用的跨域方法原理详解
  2. JavaScript 跨域总结与解决办法
  3. 前端常见跨域解决方案(全)
  4. 跨浏览器 tab 页的通信解决方案尝试
  5. 详解 CORS 跨域资源共享