跳到主要內容

contextBridge

歷史

在隔離的上下文之間建立安全、雙向、同步的橋樑

進程:渲染器

下面提供一個範例,說明如何從隔離的預載腳本向渲染器公開 API

// Preload (Isolated World)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (Main World)

window.electron.doThing()

詞彙表

主世界

「主世界」是您的主要渲染器程式碼在其中執行的 JavaScript 上下文。預設情況下,您在渲染器中載入的頁面會在該世界中執行程式碼。

隔離世界

當您的 webPreferences 中啟用 contextIsolation 時(這是 Electron 12.0.0 以來的預設行為),您的 preload 腳本會在「隔離世界」中執行。您可以在安全性文件中閱讀更多關於上下文隔離及其影響的資訊。

方法

contextBridge 模組具有以下方法

contextBridge.exposeInMainWorld(apiKey, api)

  • apiKey 字串 - 用於將 API 注入到 window 的索引鍵。API 將可在 window[apiKey] 上存取。
  • api 任意 - 您的 API,有關此 API 是什麼以及如何運作的更多資訊如下。

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId 整數 - 要將 API 注入其中的世界的 ID。0 是預設世界,999 是 Electron 的 contextIsolation 功能所使用的世界。使用 999 將會為預載上下文公開物件。我們建議在建立隔離世界時使用 1000+。
  • apiKey 字串 - 用於將 API 注入到 window 的索引鍵。API 將可在 window[apiKey] 上存取。
  • api 任意 - 您的 API,有關此 API 是什麼以及如何運作的更多資訊如下。

用法

API

提供給exposeInMainWorldapi 必須是 FunctionstringnumberArrayboolean 或一個物件,其鍵為字串,而值為 FunctionstringnumberArrayboolean 或另一個符合相同條件的巢狀物件。

Function 值會被代理到其他上下文中,而所有其他值都會被複製凍結。API 中傳送的任何資料/原始值都會變成不可變的,而橋樑任一側的更新都不會導致另一側的更新。

下面顯示一個複雜 API 的範例

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing'),
myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))],
anAsyncFunction: async () => 123,
data: {
myFlags: ['a', 'b', 'c'],
bootTime: 1234
},
nestedAPI: {
evenDeeper: {
youCanDoThisAsMuchAsYouWant: {
fn: () => ({
returnData: 123
})
}
}
}
}
)

下面顯示 exposeInIsolatedWorld 的範例

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInIsolatedWorld(
1004,
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (In isolated world id1004)

window.electron.doThing()

API 函式

您透過 contextBridge 綁定的 Function 值會透過 Electron 代理,以確保上下文保持隔離。這會導致我們在下面概述的一些關鍵限制。

參數/錯誤/傳回類型支援

由於參數、錯誤和傳回值在透過橋樑傳送時會被複製,因此只能使用某些類型。在高層次上,如果您要使用的類型可以序列化和反序列化為相同的物件,它將會運作。為了完整起見,下面包含一個類型支援表

類型複雜性參數支援傳回值支援限制
字串簡單不適用
數字簡單不適用
布林值簡單不適用
物件複雜索引鍵必須使用此表中的「簡單」類型來支援。此表中必須支援值。原型修改會被捨棄。傳送自訂類別將會複製值,但不會複製原型。
陣列複雜Object 類型相同的限制
錯誤複雜擲出的錯誤也會被複製,這可能會導致錯誤的訊息和堆疊追蹤由於在不同的上下文中擲出而略有變化,並且 Error 物件上的任何自訂屬性將會遺失
Promise複雜不適用
函式複雜原型修改會被捨棄。傳送類別或建構函式將無法運作。
可複製的類型簡單請參閱有關可複製類型的連結文件
元素複雜原型修改會被捨棄。傳送自訂元素將無法運作。
Blob複雜不適用
符號不適用符號無法在上下文之間複製,因此會被捨棄

如果您關心的類型不在上表中,則可能不受支援。

公開 ipcRenderer

嘗試將整個 ipcRenderer 模組作為物件透過 contextBridge 傳送,將會在橋樑的接收端產生一個空物件。完整地傳送 ipcRenderer 可以讓任何程式碼傳送任何訊息,這是一種安全隱憂。若要透過 ipcRenderer 進行互動,請提供如下所示的安全包裝

// Preload (Isolated World)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// Renderer (Main World)
window.electron.onMyEventName(data => { /* ... */ })

公開 Node 全域符號

預載腳本可以使用 contextBridge 來讓您的渲染器存取 Node API。上面描述的支援類型表也適用於您透過 contextBridge 公開的 Node API。請注意,許多 Node API 都授予對本機系統資源的存取權。對於您公開給不受信任的遠端內容的全域變數和 API,請務必非常謹慎。

const { contextBridge } = require('electron')
const crypto = require('node:crypto')
contextBridge.exposeInMainWorld('nodeCrypto', {
sha256sum (data) {
const hash = crypto.createHash('sha256')
hash.update(data)
return hash.digest('hex')
}
})