Skip to main content

contextBridge

History

在隔离上下文之间创建一个安全的、双向的、同步的桥梁

进程: 渲染器

🌐 Process: Renderer

下面给出了从独立的预加载脚本向渲染器公开 API 的示例:

🌐 An example of exposing an API to a renderer from an isolated preload script is given below:

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

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

window.electron.doThing()

词汇表

🌐 Glossary

主世界

🌐 Main World

“主世界”是你的主要渲染器代码运行的 JavaScript 上下文。默认情况下,你在渲染器中加载的页面会在这个世界中执行代码。

🌐 The "Main World" is the JavaScript context that your main renderer code runs in. By default, the page you load in your renderer executes code in this world.

孤立的世界

🌐 Isolated World

当在你的 webPreferences 中启用 contextIsolation 时(自 Electron 12.0.0 起这是默认行为),你的 preload 脚本会在“隔离环境”中运行。你可以在安全性 文档中了解更多关于上下文隔离及其影响的信息。

🌐 When contextIsolation is enabled in your webPreferences (this is the default behavior since Electron 12.0.0), your preload scripts run in an "Isolated World". You can read more about context isolation and what it affects in the security docs.

方法

🌐 Methods

contextBridge 模块具有以下方法:

🌐 The contextBridge module has the following methods:

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) 实验性

🌐 contextBridge.executeInMainWorld(executionScript) Experimental

  • executionScript 对象
    • func (...args: any[]) => any - 一个要执行的 JavaScript 函数。此函数将被序列化,这意味着任何绑定的参数和执行上下文都将丢失。
    • args any[](可选)- 要传递给所提供函数的参数数组。这些参数将在不同环境之间根据支持类型表进行复制。

返回 any - 从主世界执行函数后得到的结果值的副本。 参见表格 了解值在不同世界之间是如何复制的。

🌐 Returns any - A copy of the resulting value from executing the function in the main world. Refer to the table on how values are copied between worlds.

用法

🌐 Usage

应用接口

🌐 API

提供给 exposeInMainWorldapi 必须是 FunctionstringnumberArrayboolean,或者是一个键为字符串、值为 FunctionstringnumberArrayboolean 或另一个满足相同条件的嵌套对象的对象。

🌐 The api provided to exposeInMainWorld must be a Function, string, number, Array, boolean, or an object whose keys are strings and values are a Function, string, number, Array, boolean, or another nested object that meets the same conditions.

Function 值会被代理到其他上下文,所有其他值都会被复制冻结。通过 API 发送的任何数据/原始类型都会变为不可变,并且桥接两端的更新不会影响另一端的更新。

复杂 API 的示例如下所示:

🌐 An example of a complex API is shown below:

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 的一个示例:

🌐 An example of exposeInIsolatedWorld is shown below:

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

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

window.electron.doThing()

API 函数

🌐 API Functions

通过 contextBridge 绑定的 Function 值会通过 Electron 进行代理,以确保上下文保持隔离。这会导致我们在下面概述的一些关键限制。

参数/错误/返回类型支持

🌐 Parameter / Error / Return Type support

由于在通过桥发送时参数、错误和返回值是复制的,因此只有某些类型可以使用。 从高层次来看,如果你想使用的类型可以被序列化和反序列化为相同的对象,那么它是可行的。下面包含了一张类型支持的表,以便完整说明:

🌐 Because parameters, errors and return values are copied when they are sent over the bridge, there are only certain types that can be used. At a high level, if the type you want to use can be serialized and deserialized into the same object it will work. A table of type support has been included below for completeness:

TypeComplexityParameter SupportReturn Value SupportLimitations
stringSimpleN/A
numberSimpleN/A
booleanSimpleN/A
ObjectComplexKeys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype.
ArrayComplexSame limitations as the Object type
ErrorComplexErrors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object will be lost
PromiseComplexN/A
FunctionComplexPrototype modifications are dropped. Sending classes or constructors will not work.
Cloneable TypesSimpleSee the linked document on cloneable types
ElementComplexPrototype modifications are dropped. Sending custom elements will not work.
BlobComplexN/A
VideoFrameComplexN/A
SymbolN/ASymbols cannot be copied across contexts so they are dropped

如果你关心的类型不在上表中,则可能不支持。

🌐 If the type you care about is not in the above table, it is probably not supported.

公开 ipcRenderer

🌐 Exposing ipcRenderer

尝试将整个 ipcRenderer 模块作为对象通过 contextBridge 发送会导致桥接接收端得到一个空对象。完整地通过 ipcRenderer 发送可能会让任何代码发送任意消息,这是一种安全隐患。要通过 ipcRenderer 进行交互,可以提供如下安全封装器:

🌐 Attempting to send the entire ipcRenderer module as an object over the contextBridge will result in an empty object on the receiving side of the bridge. Sending over ipcRenderer in full can let any code send any message, which is a security footgun. To interact through ipcRenderer, provide a safe wrapper like below:

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

公开节点全局符号

🌐 Exposing Node Global Symbols

contextBridge 可以被预加载脚本使用,从而让你的渲染进程访问 Node API。
上面描述的支持类型表同样适用于你通过 contextBridge 暴露的 Node API。
请注意,许多 Node API 会访问本地系统资源。
对哪些全局对象和 API 暴露给不受信任的远程内容要非常谨慎。

🌐 The contextBridge can be used by the preload script to give your renderer access to Node APIs. The table of supported types described above also applies to Node APIs that you expose through contextBridge. Please note that many Node APIs grant access to local system resources. Be very cautious about which globals and APIs you expose to untrusted remote content.

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')
}
})