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
提供給 exposeInMainWorld
的 api
必須是 Function
、string
、number
、Array
、boolean
,或是一個物件,其鍵為字串,值為 Function
、string
、number
、Array
、boolean
,或是另一個符合相同條件的巢狀物件。
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 代理,以確保上下文保持隔離。這會導致我們在下面概述的一些主要限制。
參數 / 錯誤 / 傳回類型支援
由於參數、錯誤和傳回值在透過橋樑傳送時會被複製,因此只能使用某些類型。在高層次上,如果您要使用的類型可以序列化和反序列化為相同的物件,它就會運作。為了完整起見,下面包含了一個類型支援表
類型 | 複雜度 | 參數支援 | 傳回值支援 | 限制 |
---|---|---|---|---|
string | Simple | ✅ | ✅ | 不適用 |
number | Simple | ✅ | ✅ | 不適用 |
boolean | Simple | ✅ | ✅ | 不適用 |
Object | Complex | ✅ | ✅ | 鍵必須僅使用此表中的「簡單」類型來支援。值必須在此表中支援。原型修改將被捨棄。傳送自訂類別將複製值,但不會複製原型。 |
Array | Complex | ✅ | ✅ | 與 Object 類型相同的限制 |
Error | Complex | ✅ | ✅ | 拋出的錯誤也會被複製,這可能會導致錯誤的訊息和堆疊追蹤略有變化,因為它們是在不同的上下文中拋出的,並且 Error 物件上的任何自訂屬性將會遺失 |
Promise | Complex | ✅ | ✅ | 不適用 |
Function | Complex | ✅ | ✅ | 原型修改將被捨棄。傳送類別或建構函式將無法運作。 |
Cloneable Types | Simple | ✅ | ✅ | 請參閱關於可複製類型的連結文件 |
Element | Complex | ✅ | ✅ | 原型修改將被捨棄。傳送自訂元素將無法運作。 |
Blob | Complex | ✅ | ✅ | 不適用 |
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')
}
})