基于 postMessage 和 localStorage 的跨域本地存储方案

安·记 2014-09-07 2099 阅读

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 跨域的更多相关文章

  1. HTML5 postMessage 跨域交换数据

    前言 之前简单讲解了利用script标签(jsonp)以及iframe标签(window.name.location.hash)来跨域交换数据,今天我们来学习一下HTML5的api,利用postMes ...

  2. (二)文档请求不同源之window.postMessage跨域

    一.基本原理 HTML5为了解决跨域,引入了跨文档通信API(Cross-document messaging).这个API为window对象新增了一个window.postMessage方法,允许跨 ...

  3. HTML5之worker开启JS多线程模式及window.postMessage跨域

    worker概述 worker基本使用 window下的postMessage worker多线程的应用 一.worker概述 web worker实际上是开启js异步执行的一种方式.在html5之前 ...

  4. 解决postMessage跨域问题

    在HTML5中新增了postMessage方法,postMessage可以实现跨文档消息传输(Cross Document Messaging),Internet Explorer 8, Firefo ...

  5. H5新增的postMessage跨域解决方案Demo

    Demo背景:html中使用iframe嵌入了跨域的vue项目,在html中将参数传入到跨越的vue项目中. 向跨越的子窗口中发送数据 function sendMessage(data) { // ...

  6. 浅谈postMessage跨域通信与localStorage实现跨域共享

    https://www.cnblogs.com/tyrion1990/p/8134384.html

  7. JavaScript 跨域:window.postMessage 实现跨域通信

    JavaScript 跨域方式实现方式有很多,之前,一篇文章中提到了 JSONP 形式实现跨域.本文将介绍 HTML5 新增的 api 实现跨域:window.postMessage . 1 othe ...

  8. 使用 iframe + postMessage 实现跨域通信

    在实际项目开发中可能会碰到在 a.com 页面中嵌套 b.com 页面,这时第一反应是使用 iframe,但是产品又提出在 a.com 中操作,b.com 中进行显示,或者相反. 1.postMess ...

  9. HTML5:使用postMessage实现Ajax跨域请求

    HTML5:使用postMessage实现Ajax跨域请求 由于同源策略的限制,Javascript存在跨域通信的问题,典型的跨域问题有iframe与父级的通信等. 常规的几种解决方法: (1) do ...

随机推荐

  1. Java11-ZGC

    Java 11包含一个全新的垃圾收集器--ZGC,它由Oracle开发,承诺在数TB的堆上具有非常低的暂停时间. 在本文中,我们将介绍开发新GC的动机,技术概述以及由ZGC开启的一些可能性. 那么为什 ...

  2. 手把手教你springboot中导出数据到excel中

    手把手教你springboot中导出数据到excel中 问题来源: 前一段时间公司的项目有个导出数据的需求,要求能够实现全部导出也可以多选批量导出(虽然不是我负责的,我自己研究了研究),我们的项目是x ...

  3. SON Web Tokens 工具类 [ JwtUtil ]

    pom.xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt< ...

  4. 「面试」拿到B站的意向书

    此次B站服务端开发面试之旅可谓惊险,不过通过对大部分面试题套路的掌握,不出意外还是拿下了,下面我们来看看这些骚题是不是常见的不能再常见的了.这些面试题看了就能面上?当然不是,只是通过这些题让自己知道所 ...

  5. vs工程生成dll文件及其调用方法

    转载:https://blog.csdn.net/weixin_44536482/article/details/91519413 vs工程生成dll文件及其调用方法                  ...

  6. Serial.begin

    串口波特率的设置:通常我们使用Serial.begin(speed)来完成串口的初始化,这种方式,只能配置串口的波特率. 使用Serial.begin(speed, config)可以配置数据位.校验 ...

  7. 【题解】PTA-Little Bird

    Link 单调队列板子. 题目大意:一个点可以由距离它不超过\(k\)的点跳过来,如果那个点比它高就不需要花费体力,否则花费\(1\)的体力.问走到\(n\)的最小体力,多组询问. 显然的转移方程,设 ...

  8. Keil ARm新建项目

    一.新建一个工程 选好芯片后确认,完成创建 二.新建一个文件 保存为后缀名为*.c的文件 三.把文件添加进项目里面 四.测试 发现有警告 五.给项目添加特定的文件,去除警告或错误 现在保存项目的文件夹 ...

  9. CPU 执行程序的秘密,藏在了这 15 张图里

    前言 代码写了那么多,你知道 a = 1 + 2 这条代码是怎么被 CPU 执行的吗? 软件用了那么多,你知道软件的 32 位和 64 位之间的区别吗?再来 32 位的操作系统可以运行在 64 位的电 ...

  10. 虚拟主机和ECS的选择——有的坑你可以不躺,有的钱你可以不花(一)

    一直想做网站,由于最开始虚拟主机有优惠,所以三年前买了虚拟主机,后来一直续费,间歇性使用过,发现很多功能都不行​. 昨天准备买新的,然后想起学生购买有优惠,于是开始了学生认证之旅​. 首先,看一下之前 ...