postMessage
是一個強大的方法,允許在不同瀏覽器視窗(包括標籤頁、iframe、彈出視窗)或同一視窗的不同 JavaScript 執行上下文(例如,主執行緒和 Web Worker)之間安全地進行跨域通訊。它繞過了同源策略的限制,實現了靈活的資料交換。
核心理解:
postMessage
的工作機制類似於傳送訊息。源視窗使用 postMessage
方法向目標視窗傳送訊息,目標視窗透過監聽 message
事件來接收訊息。
使用方法:
源視窗:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
: 目標視窗的引用,例如iframe.contentWindow
或透過window.open
返回的物件。message
: 要傳送的資料,可以是任何可以結構化克隆的 JavaScript 值,包括字串、數字、布林值、陣列、物件等。需要注意的是,一些物件,例如函式和 DOM 節點,是無法被克隆的。targetOrigin
: 指定目標視窗的 origin(協議 + 主機 + 埠)。"*" 表示任何 origin,但為了安全起見,強烈建議指定具體的 origin。transfer
(可選): 一個可轉移物件的陣列,允許高效地轉移 ArrayBuffer 等二進位制資料的控制權,避免了資料的複製。
目標視窗:
window.addEventListener('message', function(event) {
if (event.origin !== expectedOrigin) {
return; // 安全檢查,忽略來自非預期 origin 的訊息
}
// 處理接收到的訊息
console.log('Received message:', event.data);
}, false);
event.data
: 接收到的訊息資料。event.origin
: 傳送訊息的視窗的 origin。event.source
: 傳送訊息的視窗的引用,可用於回信。
運用場景:
-
iframe 通訊: 在頁面嵌入 iframe,並需要父子視窗或不同 iframe 之間進行資料交換時,
postMessage
是理想的解決方案。例如,iframe 內的頁面載入完成後通知父頁面調整 iframe 高度。 -
跨域通訊: 當需要與不同域的頁面進行通訊時,
postMessage
提供了一種安全可靠的方式。例如,在一個頁面中整合來自其他域的第三方 widget。 -
Web Worker 通訊: 主執行緒和 Web Worker 之間可以透過
postMessage
進行資料交換,實現並行處理,避免阻塞主執行緒。 -
OAuth 2.0 授權: 在 OAuth 2.0 的 implicit flow 中,授權伺服器透過
postMessage
將 access token 傳送回客戶端。 -
瀏覽器擴充套件程式: 瀏覽器擴充套件程式的不同元件之間,例如 popup 頁面和 background script,可以使用
postMessage
進行通訊。 -
實時聊天應用: 結合 WebSocket 或 Server-Sent Events,
postMessage
可以用於在多個客戶端之間傳遞實時訊息。
安全注意事項:
- 始終驗證
event.origin
,確保訊息來自預期的 origin,防止惡意攻擊。 - 避免使用 "*" 作為
targetOrigin
,除非你確定任何 origin 的訊息都是可接受的。 - 謹慎處理接收到的訊息,避免執行來自不可信來源的程式碼。
透過理解 postMessage
的工作機制和運用場景,可以更好地利用它構建更靈活、更安全的 Web 應用。