跳到主要內容

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 可以是什麼以及其運作方式的更多資訊,請參閱下文。

contextBridge.executeInMainWorld(executionScript) 實驗性

  • executionScript 物件
    • func (...args: any[]) => any - 要執行的 JavaScript 函數。此函數將被序列化,這表示任何綁定的參數和執行上下文都將遺失。
    • args 任意類型[] (選填) - 要傳遞給所提供函數的參數陣列。這些參數將根據支援的類型表在世界之間複製。

傳回 any - 從在主世界中執行函數所產生值的副本。請參閱表格,了解值如何在世界之間複製。

用法

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 代理,以確保上下文保持隔離。這會導致我們在下面概述的一些主要限制。

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

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

類型複雜度參數支援傳回值支援限制
stringSimple不適用
numberSimple不適用
booleanSimple不適用
ObjectComplex鍵必須僅使用此表中的「簡單」類型來支援。值必須在此表中支援。原型修改將被捨棄。傳送自訂類別將複製值,但不會複製原型。
ArrayComplexObject 類型相同的限制
ErrorComplex拋出的錯誤也會被複製,這可能會導致錯誤的訊息和堆疊追蹤略有變化,因為它們是在不同的上下文中拋出的,並且 Error 物件上的任何自訂屬性將會遺失
PromiseComplex不適用
FunctionComplex原型修改將被捨棄。傳送類別或建構函式將無法運作。
Cloneable TypesSimple請參閱關於可複製類型的連結文件
ElementComplex原型修改將被捨棄。傳送自訂元素將無法運作。
BlobComplex不適用
Symbol不適用符號無法跨上下文複製,因此它們會被捨棄

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

公開 ipcRenderer

嘗試透過 contextBridge 將整個 ipcRenderer 模組作為物件傳送,將導致橋樑接收端出現空物件。完整傳送 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')
}
})