共计 2426 个字符,预计需要花费 7 分钟才能阅读完成。
敌人的网站有个需要:要从 A 域名迁徙到 B 域名。所有内容不变,只是更改域名。这个需要不简单,实践上改下配置而后 301 即可。但这个网站是纯动态网站,用户数据都存在 localStorage
里,所以他心愿可能主动帮用户把数据也迁徙到新域名。
咱们晓得,localStorage
是依照域名存储的,B 网站无法访问 A 网站的 localStorage
。所以咱们就须要一些非凡的伎俩来实现需求。通过一些调研,咱们筹备应用 postMessage()
来实现这个需要。
大体的计划如下:
首先,减少 migrate.html 页面。 这个页面不须要其它具体性能,只有侦听 message
事件,并且把 localStorage
传出即可。
<!-- migrate.html --> | |
<script> | |
window.addEventListener('message', function (message) {const { origin, source} = message; | |
// 验证起源,只承受咱们本人的域名发来的申请 | |
if (origin !== 'https://wordleunlimited.me') return; | |
const local = localStorage.getItem('wordle'); | |
// `source` 是浏览器主动填充的,即调用 `postMessage` 的起源。作为跨域 iframe 里的页面,拿不到外层 window,只能通过这种形式往回传递数据。source.postMessage({ | |
type: 'migrate', | |
stored: local, | |
}, 'https://wordleunlimited.me'); | |
}); | |
</script> |
而后,在利用里减少 <iframe>
,因为我用 Vue3,所以这里也用 Vue 组件的形式解决。
<!-- App.vue --> | |
<template lang="pug"> | |
migrate-domain(v-if="needMigrate") | |
</template> | |
<script setup> | |
// 我会把迁徙的状态长久化,免得重复提醒打搅用户 | |
const needMigrate = location.hostname === 'wordleunlimited.me' && !store.state.migrated19; | |
</script> |
<!-- migrate-domain.vue --> | |
<script lang="ts" setup> | |
import {ref} from "vue"; | |
// 我的项目启动得早,还在用 vuex | |
import {useStore} from "vuex"; | |
import {key} from "@/store"; | |
const store = useStore(key); | |
const migrateIFrame = ref<HTMLIFrameElement>(); | |
// migrate.html 接到申请后,验证起源,而后会把 localStorage 的数据发回。咱们用这个函数接管。window.addEventListener('message', message => {const { origin, data} = message; | |
// 同样验证起源 | |
if (origin !== 'https://mywordle.org' && origin !== 'https://mywordgame.com') return; | |
const {type, stored} = data; | |
if (type !== 'migrate') return; | |
if (stored) { | |
// 迁徙数据时,需退出非凡标记,用来标记“已迁徙”状态 | |
localStorage.setItem('wordle', stored.replace(/}$/, ',"migrated19": true}')); | |
// 很奇怪,间接 reload 可能会迁徙失败,所以这里略微等一下 | |
setTimeout(() => {if (confirm('Data migrated, reload the page?')) {location.reload(); | |
} | |
}, 100); | |
} | |
}); | |
// iframe 加载完即执行这段 JS,向 iframe 内的页面传递迁徙申请 | |
function onLoad() { | |
const contentWindow = migrateIFrame.value?.contentWindow; | |
if (contentWindow) {contentWindow.postMessage('migrate', 'https://mywordle.org'); | |
} else {console.warn('no content window'); | |
} | |
} | |
</script> | |
<template lang="pug"> | |
iframe( | |
ref="migrateIFrame" | |
src="https://mywordle.org/migrate.html" | |
frameborder="no" | |
width="0" | |
height="0" | |
@load="onLoad" | |
) | |
</template> | |
<style scoped> | |
iframe { | |
width: 0; | |
height: 0; | |
} | |
</style> |
至此,性能实现。
如此一来,老用户关上网站后,会被跳转到新域名。而后利用 JS 会查看 localStorage
里存储的数据,如果没有迁徙过,就会应用 <iframe>
加载老域名下的 migrate.html
。期待指标页面加载实现之后,调用 postMessage()
发送迁徙申请。接下里,migrate.html
接到申请后,返回之前存储的数据。新域名贮存之后,提醒刷新。
次要的坑在于 <iframe>
里的页面无奈间接跟跨域页面通信,所以须要父页面先找到子页面,发动申请;而后子页面再把数据回传给父页面。其它方面应该就是个别的 API 调用,以及体验性问题。
心愿本文对大家有帮忙。如果各位对 postMessage() 或者其它相干技术有问题的话,欢送留言交换。
本文参加了 SegmentFault 思否写作挑战赛,欢送正在浏览的你也退出。