浏览器跨域解决方案

同源政策是指如果两个网站不同源。则两网站不能访问对方的:
1.cookie,IndexDB,LocalStorage
2.Dom节点
3.Ajax请求不能发送
  • 那同源需要满足什么呢?

    • 协议相同

    • 域名相同

    • 端口相同

  • 首先我们先来说说常用的ajax跨域需求

    • JSONP(JSONP只能发送get请求)

    JSONP是客户端与服务端跨域通信的常用方法,简单实用,兼容老式浏览器
    1.网页动态插入script标签
    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);
    };
    2.服务器收到这个请求后,会将数据放在回调函数的参数位置返回:
    
    foo({
      "ip": "8.8.8.8"
    });
    • WebSocket
      WebSocket支持不同源政策

  • Cookie

     Cookie是服务器写入浏览器的信息,必须是同源网页才能共享。不过一级域名相同,二级域名不同,允许通过设置document.domain共享Cookie。
    • 两个页面都设置document.domain = 'liuwen.com';

    • 其中一个页面设置 document.cookie = 'name = louden'

    • 另一个页面读这个cookie:var allCookie = document.cookie;

  • iframe
    如果两个网页不同源,就无法拿到对方的DOM,典型的例子就是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。

  • 父窗口获取子窗口:

document.getElementById("myIFrame").contentWindow.document
  • 子窗口获取父窗口:

window.parent.document.body

如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain即可。

如果是完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。

    - 片段标示符
    - window.name
    - 跨文档通信API
  • 片段标示符

片段标示符是URL的#后面的部分,比如
http://163.com/a.html#fragment的#fragment,如果只是改变片段标示符,页面不会重新刷新。

  • 父窗口可以把信息,写入子窗口的片段标示符:

var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
  • 子窗口可以通过监听hashchange事件得到通知:

window.onhashchange = checkMessage;

function checkMessage() {
  var message = window.location.hash;
  // ...
}
  • 同样的,子窗口也可以改变父窗口的片段标示符:

parent.location.href= target + "#" + hash;

window.name

浏览器窗口有window.name属性,这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个页面设置了这个属性,后一个网页可以读取它。

  • 父窗口先打开一个子窗口,载入一个不同源的页面,该网页将信息写入window.name属性:

window.name = data;
  • 子窗口跳回一个与主窗口同域的网址:

location = 'http://parent.url.com/xx.html';
  • 然后,主窗口就可以读取子窗口的window.name了:

var data = document.getElementById('myFrame').contentWindow.name;

优点是window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性值的变化,影响页面性能。

window.postMessage

HTML5的全新API:跨文档通信API。

父窗口
http://aaa.com
向子窗口http://bbb.com
发消息,调用postMessage方法就可以了:

var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');

posetMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即”协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。

  • 子窗口向父窗口发送消息的写法类似:

window.opener.postMessage('Nice to see you', 'http://aaa.com');
  • 父窗口和子窗口都可以通过message事件,监听对方的消息:

window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

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

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

下面可以看看几个例子:

  • 子窗口通过event.source属性引用父窗口,然后发送信息:

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  event.source.postMessage('Nice to see you!', '*');
}
  • event.origin属性可以过滤不是发送本窗口的信息:

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  if (event.origin !== 'http://aaa.com') return;
  if (event.data === 'Hello World') {
      event.source.postMessage('Hello', event.origin);
  } else {
    console.log(event.data);
  }
}

你可能感兴趣的:(跨域,ajax跨域)