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多线程
线程与进程 什么是进程? 当一个程序进入内存中运行起来它就变为一个进程.因此,进程就是一个处于运行状态的程序.同时进程具有独立功能,进程是操作系统进行资源分配和调度的独立单位. 什么是线程? 线程是进 ...
- WAF的那些事
介绍WAF 本节主要介绍WAF (Web Application Firewall, Web应用防火墙)及与其相关的知识,这里利用国际上公认的一种说法: Web应用防火墙是通过执行系列针对HTTP/H ...
- Cypress系列(60)- 运行时的截图和录屏
如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 背景 在测试运行时截图和录屏能够在测试错 ...
- POI和easyExcel
POI与easyExcel 这个东西一般用来做什么? 将用户信息导出为Excel表格(导出数据) 将Excel表中的信息录入到网站数据库(比如一些习题上传) 在开发过程中会遇到对Excel的处理,比如 ...
- Python-变量-字符串
str 字符串如何表示字符串? 单行 单引号 '' 如果字符串中有单引号就需要双引号表示,反之亦然 双引号 " " 换行表示 \ one_str = "简洁胜于优雅&qu ...
- linux_基础调优
1. 配置授时服务,使用阿里云的授时服务 echo -e "# update time\n*/5 * * * * /usr/sbin/ntpdate time1.aliyun.com &am ...
- mysql-18-function
#函数 /* 存储过程:可以有0个或多个返回,适合批量插入.批量更新 函数:有且仅有一个返回,适合处理数据后返回一个结果 */ #一.创建语法 /* create function 函数名(参数列表) ...
- C++中cstring.h和string.h的区别
转载:https://blog.csdn.net/qian_chun_qiang/article/details/80648691 1.string与cstring有什么区别 <string&g ...
- winfrom加载自定义控件、窗口pannel后闪烁问题
我用一个panel当容器,里面有好多控件,加载的时候一直闪烁. 借鉴网友的思路: 窗口初始化界面加入代码 this.DoubleBuffered = true;//设置本窗体 SetStyle(C ...
- SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期
写在前面 通过前几篇文章的学习,我们从大体上了解了shiro关于认证和授权方面的应用.在接下来的文章当中,我将通过一个demo,带领大家搭建一个SpringBoot整合Shiro的一个项目开发脚手架, ...