文章目录
  1. 1. 一. 概念
    1. 1.1. 1.1 含义关键词
    2. 1.2. 1.2 目的
    3. 1.3. 1.3 限制范围
  2. 2. 二. Cookie
  3. 3. 三. iframe 子窗口
    1. 3.1. 3.1 片段标识符
    2. 3.2. 3.2 window.name
    3. 3.3. 3.3 window.postMessage
    4. 3.4. 3.4 LocalStorage
  4. 4. 四. AJAX
    1. 4.1. 4.1 JSONP
    2. 4.2. 4.2 CORS

老调重弹,读书百遍!

这只是是笔记

一. 概念

浏览器的同源策略
同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。

1.1 含义关键词

  • 域名
  • 协议
  • 端口

1.2 目的

为了保证用户信息的安全,防止恶意的网站窃取数据。(大家熟悉的 限制跨域 cookie)最初的目的确实是为了限制 跨站访问 cookie

1.3 限制范围

随着互联网的发展,”同源政策”越来越严格。目前,如果非同源,共有三种行为受到限制。

  • Cookie、LocalStorage 和 IndexDB 无法读取。
  • DOM 无法获得。
  • AJAX 请求不能发送。

Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。
但是两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置 document.domain 共享 Cookie。
比如: http://a.ds.comhttp://b.ds.com, 那么只要设置相同的 document.domain.两个网页就可以共享 Cookie
但是注意这种方法 只能对 Cookie 和 iframe 窗口的通信有效.

三. iframe 子窗口

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

如果两个窗口一级域名相同,只是二级域名不同,那么设置 document.domain 属性,就可以规避同源政策,拿到 DOM。

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

  • 片段标识符(fragment identifier)即 hash
  • window.name
  • 跨文档通信 API(Cross-document messaging)

3.1 片段标识符

片段标识符(fragment identifier)指的是,URL 的#号后面的部分,比如http://example.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面不会重新刷新。

父窗口可以把信息,写入子窗口的片段标识符。

1
2
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;

子窗口通过监听 hashchange 事件得到通知。

1
2
3
4
5
window.onhashchange = checkMessage;
function checkMessage() {
var message = window.location.hash;
// ...
}

反之亦然。

3.2 window.name

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

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

1
window.name = data;

接着,子窗口跳回一个与主窗口同域的网址,然后主窗口就可以读取子窗口的 window.name 了。

缺点需要 在设置 name 属性之后,更新 url,影响页面性能,操作繁琐。

3.3 window.postMessage

这个方法才是合理的解决方案,以上那些都是钻孔取巧。
HTML5 为了解决这个问题,引入了一个全新的 API:跨文档通信 API(Cross-document messaging)。
这个 API 为 window 对象新增了一个 window.postMessage 方法,允许跨窗口通信,不论这两个窗口是否同源。

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

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

然后监听消息使用 message 事件:

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

3.4 LocalStorage

同理,上面讲过的 postMessage 也可以用来实现 localstorage 传递的桥梁.
比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window.onmessage = function(e) {
if (e.origin !== 'http://bbb.com') return;
var payload = JSON.parse(e.data);
switch (payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, 'http://aaa.com');
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
};

四. AJAX

同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。

除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),还有以下方法规避这个限制。

  • JSONP
  • CORS

4.1 JSONP

JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。

它的基本思想是,网页通过添加一个 script 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

首先,网页动态插入 script 元素,由它向跨源网址发出请求。

1
2
3
4
5
6
7
8
9
10
11
12
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);
};

服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

1
2
3
foo({
"ip": "8.8.8.8"
});

4.2 CORS

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

原文出处

文章目录
  1. 1. 一. 概念
    1. 1.1. 1.1 含义关键词
    2. 1.2. 1.2 目的
    3. 1.3. 1.3 限制范围
  2. 2. 二. Cookie
  3. 3. 三. iframe 子窗口
    1. 3.1. 3.1 片段标识符
    2. 3.2. 3.2 window.name
    3. 3.3. 3.3 window.postMessage
    4. 3.4. 3.4 LocalStorage
  4. 4. 四. AJAX
    1. 4.1. 4.1 JSONP
    2. 4.2. 4.2 CORS
顶部