1. 同源策略

为了保证用户信息的安全,防止恶意的网站数据窃取。浏览器制定了「同源策略」。

具体来说,就是一个域名下的网址,只能请求同协议,同域名,同端口下的接口数据。

2. 如何跨域

跨域通信分为两种:

  1. 不同源的页面互相发送信息

解决方案

  1. window.name
  2. document.domain
  3. window.postMessage
  1. 请求不同源网站的接口

解决方案

  1. JONSP,
  2. WebSocket
  3. CORS
  4. 反向代理

3. JSONP

这种方法之所以能够使用是因为同源策略并没有限制 <script> 标签引用资源。我们可以通过创建一个 script 向服务端发起请求,服务器收到请求后,将数据放在一个指定名字的回调函数中传回来。

下面看具体实现:

  1. /*
  2. url: 请求的rul
  3. jsonCallBack: 回调函数名称
  4. success: 请求成功时对数据进行处理的函数
  5. */
  6. const jsonp = (url, jsonCallBack, sucesss) {
  7. const Script = document.creatElement('script');
  8. Script.setAttribute('src', url);
  9. Script.async = true;
  10. Script.type = 'text/javascript'
  11. window[jsonCallback] = function(data) {
  12. success && success(data);
  13. }
  14. document.getElementsByTagName('head')[0].appendChild(Script)
  15. }
  16. // 使用
  17. jsonp('http://xxx?callback=callback', 'callback', data => console.log(data))

这种方式优点在于简单适用,老式浏览器全部支持,服务器改造非常小。

但缺点在于只能用于 GET 请求。

4. CORS

CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。

实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。

具体用法可见 CORS通信-阮一峰

与 jsonp 比较:

CORS与JSONP的使用目的相同,但是比JSONP更强大。 JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

5. document.domain

这种方法用于两个页面,后者 iframe 嵌套的网页,一级域名相同的情况。比如说 abc.d.commm.d.com

使用方法:在两个页面设置相同的 docuement.domain

  1. // A
  2. documnet.domain = 'd.com'
  3. document.cookie = "test1=hello";
  4. // B
  5. document.domain = 'd.com';
  6. const allCooki = document.cooki;

6. window.postMessage

这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。

页面通过 window.postMessage() 方式进行发送消息,这个方法接受两个参数,分别是发送的信息和目标窗口的源(即“协议 + 域名 + 端口”),第二个参也可以设置为 *,表示不限制域名,向所有窗口发送。

而接受的一方通过监听 Message 事件,得到对方发来的消息。

父窗口向子窗口发送消息:

  1. const popup = window.open('http://bbb.com', title);
  2. popup.postMessage('hello world', 'http://bbb.com')

子窗口监听消息:

  1. window.addEventListener('message', function(e) {
  2. console.log(e.data)
  3. })

message 事件的事件对象 event,提供三个属性:

  • event.source: 发送消息的窗口
  • event.origin: 消息发向的网址
  • event.data: 消息内容

通常我们可以根据 event.origin 来过滤掉不该发送过来的数据,我们还可以通过 event.source 引用来源窗口。

  1. window.addEventListener('message', receiveMessage);
  2. function receiveMessage(event) {
  3. if (event.origin !== 'http://aaa.com') return;
  4. if (event.data === 'Hello World') {
  5. event.source.postMessage('Hello', event.origin);
  6. } else {
  7. console.log(event.data);
  8. }
  9. }

参考

JavaScript 标准参考教程