Skip to main content

contextBridge

History

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

¥Create a safe, bi-directional, synchronous bridge across isolated contexts

进程:渲染器

¥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 脚本将在 "孤立的世界" 中运行。你可以在 security 文档中阅读有关上下文隔离及其影响的更多信息。

¥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] 上访问。

    ¥apiKey string - The key to inject the API onto window with. The API will be accessible on window[apiKey].

  • api 任意 - 你的 API,有关此 API 是什么及其工作原理的更多信息如下。

    ¥api any - Your API, more information on what this API can be and how it works is available below.

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId 整数 - 要注入 API 的世界的 ID。0 是默认世界,999 是 Electron 的 contextIsolation 功能使用的世界。使用 999 会公开预加载上下文的对象。我们建议在创建隔离世界时使用 1000+。

    ¥worldId Integer - The ID of the world to inject the API into. 0 is the default world, 999 is the world used by Electron's contextIsolation feature. Using 999 would expose the object for preload context. We recommend using 1000+ while creating isolated world.

  • apiKey 字符串 - 将 API 注入 window 的关键。该 API 将在 window[apiKey] 上访问。

    ¥apiKey string - The key to inject the API onto window with. The API will be accessible on window[apiKey].

  • api 任意 - 你的 API,有关此 API 是什么及其工作原理的更多信息如下。

    ¥api any - Your API, more information on what this API can be and how it works is available below.

用法

¥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 中发送的任何数据/基础类型都变得不可变,并且桥两侧的更新不会导致另一侧的更新。

¥Function values are proxied to the other context and all other values are copied and frozen. Any data / primitives sent in the API become immutable and updates on either side of the bridge do not result in an update on the other side.

复杂 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 进行代理,以确保上下文保持隔离。这导致了我们在下面概述的一些关键限制。

¥Function values that you bind through the contextBridge are proxied through Electron to ensure that contexts remain isolated. This results in some key limitations that we've outlined below.

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

¥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:

类型复杂参数支持返回值支持局限性
string简单的不适用
number简单的不适用
boolean简单的不适用
Object复杂的必须仅支持使用此表中的 "简单的" 类型的键。该表中必须支持值。原型修改被删除。发送自定义类将复制值,但不会复制原型。
Array复杂的Object 型相同的限制
Error复杂的抛出的错误也会被复制,这可能会导致错误的消息和堆栈跟踪由于在不同的上下文中抛出而略有变化,以及错误对象 会迷路 上的任何自定义属性
Promise复杂的不适用
Function复杂的原型修改被删除。发送类或构造函数将不起作用。
可克隆类型简单的请参阅有关可克隆类型的链接文档
Element复杂的原型修改被删除。发送自定义元素将不起作用。
Blob复杂的不适用
Symbol不适用符号不能跨上下文复制,因此它们被删除

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

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

公开 ipcRenderer

¥Exposing ipcRenderer

尝试通过 contextBridge 将整个 ipcRenderer 模块作为对象发送将导致桥接接收端出现空对象。通过 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')
}
})