那些被忽略但很好用的 Web API / PostMessage

亲像爱情的限时批~

各位有想过该如何跟其他页面进行沟通吗?如果在A页面点击了一个按钮,能不能够让B页面发生变化或执行动作呢?别说不可能,今天要介绍的 PostMessage 便能够达成这样的效果。


PostMessage

一般来说,不同的页面要相互沟通的话,它们的 Domain 必须相同,然後通常就会使用 LocalStorage 搭配 storage 事件来进行沟通,但 PostMessage 神奇的地方就在於它可以越过这项限制,让我们甚至可以跟不同源的网站页面进行沟通,这样就能解决前端最讨厌的 CORS 问题了。

虽然 PostMessage 可以跨域沟通,不过当然也要对方愿意且有撰写对应的机制程序码,要不然世界就大乱了 XD

 

# otherWindow.postMessage

PostMessage API 底下就是只有 postMessage 这个 method,非常的单纯,却也无比强大,其中 otherWindow 所指的是「目前分页以外的 Window」,这个 Window 可以是利用 window.open 执行返回的 Window 物件,或是一个 iframe 元素的 contentWindow,而也就是讯息要送达的目的地。

另外 postMessage 还必须传入两个参数:

  • message: 第一个是你要传送的讯息,任何型别格式都可以接受。
  • targetOrigin: 第二个则是设定「能够接收本次讯息」的网页 Origin,必须要是在这个 Domain 底下的页面才能接收到讯息。
const url = "https://maxleebk.com//2021/09/28/webApi/webApi-15/";
const otherPage = window.open(url);
otherPage.postMessage("Hi,Max", "https://maxleebk.com/");

以上面的例子来说,我们先利用 window.open 打开了一个作者本人的部落格分页,而该分页的 Window 已经被储存在 otherPage 中,再来我们就利用 postMessage 传递一个字传,并且利用 targetOrigin 来确保一定要是 https://maxleebk.com/ 底下的页面才能真正接受到讯息。

你该注意:targetOrigin 这个参数建议一定要传入并填妥,不然讯息有可能会被刻意拦截,导致无法预期的安全性问题。

 

# Window:message Event

讯息有传送的一方,自然也要有接收的一方,而接收方要顺利接到讯息的话,只要在 window 上监听 message 这个事件即可,而讯息的部分则会被放在 Event 物件的 data 属性里:

window.addEventListener("message", function (event) {
  console.log(event.data);
});

所以只要你想传送的网站中,有打开一个这样的通道,那你就可以透过 PostMessage 来与之沟通,不过接收方也不可能所有的讯息都照单全收,要是我们今天身为接收方,那应该要像下方这样做一些防御。

在 Event 物件中还有一个 origin 属性,可以用来获取传送方的来源,所以我们可以利用它来过滤那些不在信任范围的网址:

window.addEventListener("message", function (event) {
  // 如果讯息不是来自於 IT邦帮忙 那就不执行任何动作
  if (event.origin !== "https://ithelp.ithome.com.tw") return;
  console.log(event.data);
});

当然了,信息往来总不能只有单向,如果接收方要回信的话,只要利用 Event 物件中的 source 属性就可以进行讯息的传送:

window.addEventListener("message", function (event) {
  if (event.origin !== "https://ithelp.ithome.com.tw") return;
  console.log(event.data);
  event.source.postMessage("hi,IT邦帮忙", event.origin);
});

透过 PostMessage 讯息的相互传递,我们就可以不受同源政策的限制,向其他网域的网页请求资料了,或利用讯息的格式判定来执行其他页面的动作等等...

window.addEventListener("message", function (event) {
  axios.get("/user", event.data.id).then((res) => {
    event.source.postMessage(res, event.origin);
  });
});

window.addEventListener("message", function (event) {
  window[event.data.method](); // 执行指定名称的全域函式
});

 

PostMessage API 是不是非常有趣又神奇呢?或许要遇到页面沟通的情境并不多,但千万忽略了它,等到遇到了,它会是非常强大的帮手,而且应用起来也相当简单,大家如果有兴趣,随手就能写个简单的范例。


<<:  [Day15] Server - 中场来点 NGINX 设定

>>:  Day15 Hook-useRef

【心得】你今天种菜了吗? grid之路-grid的使用(5)

前言 既然可以使用grid-area为每个区域命名,并填入grid-template-areas中,...

Day24 - 静态模型 part2 (CNN)

在 CNN-based 的架构中,会使用三种不同的 CNN 架构: Basic CNN Multi-...

Swift 语言和你 SAY HELLO!!

第二十二天 各位点进来的朋友,你们好阿 小的不才只能做这个系列的文章,但还是希望分享给点进来的朋友,...

Day 1 [Python ML] 30天内容介绍

简介 之前在kaggle上面学习到了很多Python应用在Machine Learning的方法 对...

Day 5:20. Valid Parentheses

今日题目 题目连结:20. Valid Parentheses 题目主题:String, Stack...