1. 概述

  • Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。如果两个网页一级域名相同,只是次级域名不同,浏览器允许通过设置document.domain共享 Cookie。

  • 举例来说,A 网页的网址是 http://w1.example.com/a.html, B 网页的网址是 http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享 Cookie。因为浏览器通过document.domain属性来检查是否同源。

    1
    2
    // 两个网页都需要设置
    document.domain = 'example.com';

    注意,A 和 B 两个网页都需要设置document.domain属性,才能达到同源的目的。因为设置document.domain的同时,会把端口重置为null,因此如果只设置一个网页的document.domain,会导致两个网址的端口不同,还是达不到同源的目的。

  • 注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexedDB 无法通过这种方法,规避同源政策,而要使用下文介绍 PostMessage API

3. iframe

  • iframe元素可以在当前网页之中,嵌入其他网页。每个iframe元素形成自己的窗口,即有自己的window对象。iframe窗口之中的脚本,可以获得父窗口和子窗口。但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM。
  • 如果两个窗口一级域名相同,只是二级域名不同,那么设置上一节介绍的document.domain属性,就可以规避同源政策,拿到 DOM。对于完全不同源的网站,目前有两种方法,可以解决跨域窗口的通信问题。
  • 片段识别符
  • window.postMessage()
    • window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源
    • postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即“协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。
    • 父窗口和子窗口都可以通过message事件,监听对方的消息。
    • message事件的参数是事件对象event,提供以下三个属性。
      • event.source:发送消息的窗口
      • event.origin: 消息发向的网址
      • event.data: 消息内容
  • LocalStorage
    • 通过window.postMessage,读写其他窗口的 LocalStorage 也成为了可能

4. AJAX

  • 同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。
    • JSONP
    • WebSocket
    • CORS
  • JSONP

    • 它的基本思想是,网页通过添加一个 script 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      function addScriptTag(src) {
      var script = document.createElement('script');
      script.setAttribute("type","text/javascript");
      script.src = src;
      document.body.appendChild(script);
      }

      window.onload = function () {
      addScriptTag('http://example.com/ip?callback=foo');
      }

      function foo(data) {
      console.log('Your public IP address is: ' + data.ip);
      };
  • WebSocket

    • WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信
  • CORS