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 string - 用于将 API 注入 window 的密钥。该 API 将可以通过 window[apiKey] 访问。
  • api any - 你的 API,关于此 API 可以做什么以及它如何工作的更多信息如下所示。

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId Integer - 要将 API 注入的世界的 ID。0 是默认世界,999 是 Electron 的 contextIsolation 功能使用的世界。使用 999 会将对象暴露给预加载上下文。我们建议在创建隔离世界时使用 1000 以上的值。
  • apiKey string - 用于将 API 注入 window 的密钥。该 API 将可以通过 window[apiKey] 访问。
  • api any - 你的 API,关于此 API 可以做什么以及它如何工作的更多信息如下所示。

contextBridge.executeInMainWorld(executionScript) 实验性

🌐 contextBridge.executeInMainWorld(executionScript) Experimental

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

返回 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:

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

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

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