JavaScript中的跨域详解(一)
同源策略
所谓的同源策略,指的是浏览器对不同源的脚本或者文本访问方式进行的限制。
所谓同源,就是指两个页面具有相同的协议,主机(也常说域名),端口,三个要素缺一不可。
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
如果一个用户在登陆一个网站之后又去访问其他网站,如果其他网站可以读取上一个网站的cookie,就会导致个人信息泄露。
限制范围
随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制:
1、cookie、localstorage、indexDB(IndexedDB 是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索。)无法读取
2、DOM无法获得。
3、AJAX请求不能发送。
规避措施
1、cookie
Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享,但是两个网页只有一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享Cookie。
举例来说,A,http://w1.example.com/a.html B,http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。
document.domain='example.com'
A通过脚本设置一个Cookie:document.cookie='text=hello'
B网页就可以读到这个Cookie。var allCookie=document.cookie;
- 这种方法只适用于Cookie和iframe窗口,LocalStorage和IndexDB无法通过这种方法,规避同源政策。需要使用PostMessage API。另外,服务器也可以在设置Cookie的所属域名为一级域名,比如:.example.com。
Set-Cookie:key=value;domain=.example.com; path=/
这样的话,二级域名和三级域名不用做任何设置都可以读取这个Cookie。
2、iframe
如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,他们与父窗口无法通信。
比如,父窗口运行下面的命令,如果iframe不同源就会导致错误,document.getElementById('myIframe').contentWindow.document,上面的命令中,父窗口想获取子窗口的DOM,因为跨源导致报错。反之亦然。
如果两个完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。
1、片段识别符(fragment identifier)
2、window.name
3、跨文档通信API(Cross-document messaging)
片段识别符
指的是URL的#号后面的部分,比如 http://example.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面不会重新刷新。父窗口可以把信息,写入子窗口的片段标识符。
var src=originURL+'#'+data;
document.getElementById('myIFrame')
子窗口通过监听hashchange事件得到通知。
window.onhashchange=checkMessage;
function checkMessage(){
var message=window.location.hash;
}
同样的,子窗口也可以改变父窗口的片段标识符。
parent.location.href=target+'#'+data;window.name
浏览器窗口有window.name属性,这个属性的最大特点是,无论是否同源,只要在同一个窗口,前一个网页设置了这个属性,后一个网页就可以读取他。
父窗口先打开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。
window.name = data;
接着,子窗口跳回一个与主窗口同域的网址。
location = 'http://parent.url.com/xxx.html';
然后,主窗口就可以读取子窗口的window.name了。
var data = document.getElementById('myFrame').contentWindow.name;
这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。window.postMessage
上面两种方法都属于破解,HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
举例来说,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(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);
}
}
3、LocalStorage
通过window.postMessage,读写其他窗口的 LocalStorage 也成为了可能。
下面是一个例子,主窗口写入iframe子窗口的localStorage。
window.onmessage = function(e) {
if (e.origin !== 'http://bbb.com') {
return;
}
var payload = JSON.parse(e.data);
localStorage.setItem(payload.key, JSON.stringify(payload.data));
};
上面代码中,子窗口将父窗口发来的消息,写入自己的LocalStorage。
父窗口发送消息的代码如下。
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com');
加强版的子窗口接收消息的代码如下。
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;
}
};
加强版的父窗口发送消息代码如下。
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
// 存入对象
win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
// 读取对象
win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
window.onmessage = function(e) {
if (e.origin != 'http://aaa.com') return;
// "Jack"
console.log(JSON.parse(e.data).name);
};
JavaScript中的跨域详解(一)的更多相关文章
- JavaScript中的跨域详解(二)
4.AJAX 同源政策规定,AJAX请求只能发给同源的网址,否则就报错. 除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制. JSONP WebSocket C ...
- javascript中=、==、===区别详解
javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...
- JavaScript中return的用法详解
JavaScript中return的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 t ...
- javascript 中合并排序算法 详解
javascript 中合并排序算法 详解 我会通过程序的执行过程来给大家合并排序是如何排序的... 合并排序代码如下: <script type="text/javascript& ...
- javascript中的this作用域详解
javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...
- JavaScript中this的用法详解
JavaScript中this的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 thi ...
- JavaScript中的跨域
跨域是什么 跨域就是指从一个域名的网页去请求另一个域名的资源,因为JavaScript同源策略的限制,资源无法获取.比如从www.baidu.com 页面去请求 www.google.com 的资源, ...
- 跨域详解之jsonp,底层的实现原理
分享一下跨域,不仅是因为现在的工作中遇到的越来越多,而且在面试中也经常被问到. 那么什么是跨域呢,我们来看官方给出的解释:浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的(所谓同源是指,域名 ...
- JavaScript中数组Array方法详解
ECMAScript 3在Array.prototype中定义了一些很有用的操作数组的函数,这意味着这些函数作为任何数组的方法都是可用的. 1.Array.join()方法 Array.join()方 ...
随机推荐
- 基于sklearn进行文本向量化
sklearn中,计数向量化用CountVectorizer,tfidf向量化用TfidfVectorizer: import pickle from sklearn.feature_extracti ...
- 2018秋C语言程序设计(初级)作业- 第3次作业
7-1 找出最小值 #include<stdio.h> int main() { int min,i,n,count; scanf("%d",&n); for( ...
- HDU - 4339: Query(bitset暴力找下一个为1的)
题意:给定A,B长度相同的字符串,Q次操作,修改操作位单个字符修改,查询操作为询问从某点开始有多少连续相同的字符. 思路:我们把不相同的设为1,相同的设为0,那么询问就是找下一个为1的为位置,可以用线 ...
- Windows7 下python3和python2同时 安装python3和python2
1.下载python3和python2 进入python官网,链接https://www.python.org/ 选择Downloads--->Windows,点击进入就可以看到寻找想要的pyt ...
- scrapy 伪装代理和fake_userAgent的使用
伪装浏览器代理 在爬取网页是有些服务器对请求过滤的不是很高可以不用ip来伪装请求直接将自己的浏览器信息给伪装也是可以的. 第一中方法: 1.在setting.py文件中加入以下内容,这是一些浏览器的头 ...
- Spring Cloud feign 服务超时处理
Spring Cloud中,Feign和Ribbon在整合了Hystrix后,可能会出现首次调用失败的问题 造成该问题的原因 Hystrix默认的超时时间是1秒,如果超过这个时间尚未响应,将会进入fa ...
- c++重在运算符
运算符函数的定义与其他函数的定义类似,惟一的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的.运算符函数定义的一般格式如下: <返回类型说明符> opera ...
- bzoj 2406 矩阵——有源汇上下界可行流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406 二分答案.把 b 的 n 个行作为一排, m 个列作为一排,每行和每列之间连上下界为 ...
- mac系统PHP 7.1.12安装xhprof并使用[View Full Callgraph]小记
前几天从php7.0.x 升级到了php7.2.0版本, 结果装xhprof没有找到能支持对应版本的xhprof 于是又安装了一个php7.1.2的版本(brew install h) 接着安装xhp ...
- [转]nginx虚拟目录(alias与root的区别)
今天配置awstats,awstats创建出的文件目录在/home/awstats下,在nginx中加入配置后狂报404,发现还是忽略了root和alias的区别,特将修改配置记录如下: 1.失败:s ...