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 ...
随机推荐
- Hive改表结构的两个坑|避坑指南
Hive在大数据中可能是数据工程师使用的最多的组件,常见的数据仓库一般都是基于Hive搭建的,在使用Hive时候,遇到了两个奇怪的现象,今天给大家聊一下,以后遇到此类问题知道如何避坑! 坑一:改变字段 ...
- 使用koa-log4管理nodeJs日志笔记
前言 对于后端程序应用来说,日志是必不可少的,在nodeJs当中并没有自带的日志模块.最近正好使用koa框架来做后端服务,需要对日志进行分割处理,特记录下分享给大家. 一.后端代码目录结构 ├── b ...
- 从 ES6 高阶箭头函数理解函数柯里化
前言:第一次看到多个连续箭头函数是在一个 react 项目中,然鹅确认了下眼神,并不是对的人,因为看得一脸懵逼.em......于是开始各种搜索,先是知道了多个连续箭头函数就是 es6 的多次柯里化的 ...
- Spring学习(八)--Spring的AOP
自工作以后身不由己,加班无数,996.995不可控制,高高立起的flag无法完成,无奈,随波逐流,尽力而已! 1.advice通知 advice主要描述Spring AOP 围绕奥方法调用而注入的切面 ...
- Python练习题 017:三支乒乓球队出赛名单
[Python练习题 017] 两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人.已抽签决定比赛名单.有人向队员打听比赛的名单.a说他不和x比,c说他不和x,z比.请编程序找 ...
- Mysql中 int(3) 类型的含义
注意:这里的(3)代表的并不是存储在数据库中的具体的长度,以前总是会误以为int(3)只能存储3个长度的数字,int(11)就会存储11个长度的数字,这是大错特错的. 其实当我们在选择使用int的类型 ...
- Arduino PID Library
Arduino PID Library by Brett Beauregard,contact: br3ttb@gmail.com What Is PID? PID是什么 From Wikipe ...
- 十一、模拟扫码登录微信(用Django简单的布置了下页面)发送接收消息
为了能够模拟登陆QQ,并获取信息.对扫码登录微信进行了分析.简单的用了一下Django将获取的信息映射到页面上.(python3+pycharm) 主要过程就是: 1.获取二维码 2.扫码登录(有三种 ...
- 01 . OpenResty简介部署,优缺点,压测,适用场景及用Lua实现服务灰度发布
简介 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭建能够处理超高并发.扩展性极高的动态 ...
- 工信部今日向三大运营商和中国广电发放5G商用牌照
央视快讯:工信部向中国电信.中国移动.中国联通.中国广电发放5G商用牌照. 2016年5月5日,工信部向中国广播电视网络有限公司颁发了<基础电信业务经营许可证>,批准中国广播电视网络有限公 ...