postMessage 跨域
基于 postMessage 和 localStorage 的跨域本地存储方案
HTML5 的 postMessage 为解决跨域页面通信提供了一套可控的机制, 而 localStorage 则提供了易用简洁的本地存储方案? 这两者结合起来,能否实现跨域本地存储呢 ?
答案是可以的。假设有 a.com 和 b.com 两个页面。我们想通过 a 页面去修改 b 页面的本地数据。 我们需要做如下步奏:
- 在 a 页面创建一个 iframe ,嵌入 b 页面
- a 页面通过 postMessage 传递指定格式的消息给 b 页面
- b 页面解析 a 页面传递过来的消息内容,调用localStorage API 操作本地数据
- b 页面包装 localStorage 的操作结果,并通过 postMessage 传递给 a 页面
- a 页面解析 b 页面传递回来的消息内容,得到 localStorage 的操作结果
整个过程如下图:

OK,清楚了整个过程,我们就可以封装出相应的组件:CSClient.js 和 csHub.js,来完成这个过程,下面我们来简单实现一下。
先来看CSClient.js,作用于 a 页面,用于创建跨域存储实例,它提供了 get、set、del 这三个方法来操作跨域的数据:
function CSClient(url) {
this.id = this._getId();
this._init(url);
this._origin = this._getOrigin(url);
this._callbacks = {
_get: {},
_set: {},
_del: {}
}
this._bindEvent();
}
CSClient.prototype._getId = function () {
id = 0;
return function () {
return ++id;
}
}();
CSClient.prototype._init = function (url) {
var frame = document.createElement('iframe');
frame.style.display = 'none';
frame.src = url;
document.body.appendChild(frame);
this._hub = frame.contentWindow;
}
CSClient.prototype._getOrigin = function(url) {
var uri, origin;
uri = document.createElement('a');
uri.href = url;
origin = uri.protocol + '//' + uri.host;
return origin;
};
CSClient.prototype._parseMessage = function (method, key, value) {
return JSON.stringify({
method: method,
key: key,
value: value
});
}
CSClient.prototype._bindEvent = function () {
var _this = this;
window.addEventListener('message', function (event) {
var data = JSON.parse(event.data);
var error = data.error;
var result = data.result && JSON.parse(data.result) || null;
try {
_this._callbacks['_' + data.method][data.key](error, result);
}
catch (e){
console.log(e);
}
}, false);
}
CSClient.prototype.get = function (key, callback) {
this._hub.postMessage(this._parseMessage('get', key), this._origin);
this._callbacks._get[key] = callback;
}
CSClient.prototype.set = function (key, value, callback) {
this._hub.postMessage(this._parseMessage('set', key, value), this._origin);
this._callbacks._set[key] = callback;
}
CSClient.prototype.del = function (key, callback) {
this._hub.postMessage(this._parseMessage('del', key),this._origin);this._callbacks._del[key]= callback;}
使用方法如下:
var key = document.querySelector('#key');
var value = document.querySelector('#value');
var btn = document.querySelectorAll('button');
var storage = new CSClient('http://b.com');
btn[0].onclick = function (e) {
storage.get(key.value, function (err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
})
}
btn[1].onclick = function (e) {
storage.set(key.value, value.value, function (err) {
if (err) {
console.log(err);
return;
}
console.log('set ok');
})
}
btn[2].onclick = function (e) {
storage.del(key.value, function (err) {
if (err) {
console.log(err);
return;
}
console.log('del ok');
})
}
接着看 csHub.js,作用于 b 页面,用于设置跨域存储的权限、接受 client 的消息、操作本地数据。只有拥有权限的 origin ,才能操作本页面的本地数据。
var csHub = window.csHub = {
init: function (origin) {
this.originRule = origin;
},
get: function (key) {
return JSON.stringify(window.localStorage.getItem(key));
},
set: function (key, value) {
window.localStorage.setItem(key, JSON.stringify(value));
},
del: function (key) {
window.localStorage.removeItem(key);
}
};
window.addEventListener('message', function (event) {
var message = JSON.parse(event.data), result, err = null;
if (csHub.originRule.test(event.origin)) {
try {
result = csHub[message.method](message.key, message.value);
}
catch (e) {
err = {
message: e.message,
stack: e.stack
};
}
window.parent.postMessage(JSON.stringify({
error: err,
method: message.method,
key: message.key,
result: result
}), event.origin);
}
}, false);
使用方法如下:
csHub.init(/a.com$/);
以上代码都比较简单, 主要为了演示如何实现跨域存储。如果你想在项目中使用此方案。推荐使用https://github.com/zendesk/cross-storage这个库。 这个库实现了更灵活的权限机制,使用 ES6 的 promises 规范简化了操作接口, 并对浏览器的差异化做了处理,兼容到了 ie8+ 与其他现代浏览器。
postMessage 跨域的更多相关文章
- HTML5 postMessage 跨域交换数据
前言 之前简单讲解了利用script标签(jsonp)以及iframe标签(window.name.location.hash)来跨域交换数据,今天我们来学习一下HTML5的api,利用postMes ...
- (二)文档请求不同源之window.postMessage跨域
一.基本原理 HTML5为了解决跨域,引入了跨文档通信API(Cross-document messaging).这个API为window对象新增了一个window.postMessage方法,允许跨 ...
- HTML5之worker开启JS多线程模式及window.postMessage跨域
worker概述 worker基本使用 window下的postMessage worker多线程的应用 一.worker概述 web worker实际上是开启js异步执行的一种方式.在html5之前 ...
- 解决postMessage跨域问题
在HTML5中新增了postMessage方法,postMessage可以实现跨文档消息传输(Cross Document Messaging),Internet Explorer 8, Firefo ...
- H5新增的postMessage跨域解决方案Demo
Demo背景:html中使用iframe嵌入了跨域的vue项目,在html中将参数传入到跨越的vue项目中. 向跨越的子窗口中发送数据 function sendMessage(data) { // ...
- 浅谈postMessage跨域通信与localStorage实现跨域共享
https://www.cnblogs.com/tyrion1990/p/8134384.html
- JavaScript 跨域:window.postMessage 实现跨域通信
JavaScript 跨域方式实现方式有很多,之前,一篇文章中提到了 JSONP 形式实现跨域.本文将介绍 HTML5 新增的 api 实现跨域:window.postMessage . 1 othe ...
- 使用 iframe + postMessage 实现跨域通信
在实际项目开发中可能会碰到在 a.com 页面中嵌套 b.com 页面,这时第一反应是使用 iframe,但是产品又提出在 a.com 中操作,b.com 中进行显示,或者相反. 1.postMess ...
- HTML5:使用postMessage实现Ajax跨域请求
HTML5:使用postMessage实现Ajax跨域请求 由于同源策略的限制,Javascript存在跨域通信的问题,典型的跨域问题有iframe与父级的通信等. 常规的几种解决方法: (1) do ...
随机推荐
- Java基础一篇过(七)Java8--stream流
一.简介 流(stream)也是Java8的一个重要的新特性,主要是对集合(Collector)功能的增强:在上一篇文章我们简单的了解了lambda表达式,现在我们学习下流的概念:使用流可以帮助我们做 ...
- 趣图:这是拿offer极高的面试经验
扩展阅读 趣图:面试谈薪资就要这种底气 趣图:IT培训出来找工作 趣图:这是招聘超神级别的程序员?
- Oracle学习(四)SQL高级--表优化相关(序列、视图等)
INDEX(索引) 可以在表中创建索引,以便更加快速高效地查询数据. 用户无法看到索引,它们只能被用来加速搜索/查询. PS:更新一个包含索引的表需要比更新一个没有索引的表花费更多的时间,这是由于索引 ...
- 把VS Code打造成Java开发IDE
近期,公司推行正版化,本人使用的是JetBrains教育版,是不允许进行商业开发的,因此开启了艰难的备用IDE选型之路.最终,我选定了轻量级的Visual Studio Code(以下简称VS Cod ...
- spring cloud consul 服务治理
对照系统安装响应consul文件(以window为例) 解压文件之后配置环境,进入Path添加文件所在目录, 测试:在文件所在目录下进入指令操作 输入 consul agent -dev 启动成功,在 ...
- Jquery的一键上传组件OCUpload及POI解析Excel文件
第一步:将js文件引入页面 <script type="text/javascript" src="${pageContext.request.contextPat ...
- 【奇淫巧技】XSS绕过技巧
XSS记录 1.首先是弹窗函数: alert(1) prompt(1) confirm(1)eval() 2.然后是字符的编码和浏览器的解析机制: 要讲编码绕过,首先我们要理解浏览器的解析过程,浏览器 ...
- springcloud学习入门
Springcloud入门学习笔记 1. 项目初始化配置 1. 1. 新建maven工程 使用idea创建maven项目 1. 2. 在parent项目pom中导入以下依赖 <parent> ...
- Win10下设置GOPATH系统变量,查看go env没有变化
前言 最近在学习go语言,下载了golang安装包安装之后,使用go env查看环境变量,发现GOPATH已经指向默认的目录了 按照安装手册去系统变量设置了一下GOPATH,指向自定义目录 再来运行一 ...
- 2017-01-26--编译busybox总结
错误一: ox@ubuntu:busybox-1.16.0$ make menuconfig Makefile:431: *** mixed implicit and normal rules: de ...