乐趣区

关于javascript:使用-postMessage-跨域名迁移-localStorage

敌人的网站有个需要:要从 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 思否写作挑战赛,欢送正在浏览的你也退出。

退出移动版