1. 定义
Electron = 前端项目 + Chromium 浏览器(谷歌浏览器开源版本),封装了丰富的系统级 API。
2. 进程模型
Electron 采用多进程架构:
- 主进程:管理应用生命周期和窗口创建,可访问 Node.js API 和系统资源
- 渲染进程:每个窗口/页面独立运行,负责 UI 渲染和用户交互
-
预加载脚本:安全桥接层,在渲染进程启动前运行,可访问 Node.js API 并通过
contextBridge向渲染进程暴露接口 - 效率进程:通过 UtilityProcess 创建的子进程,用于执行不稳定或耗时的任务
3. IPC 进程间通信
Electron 提供三种 IPC 通信模式:
3.1 单向通信:渲染进程 → 主进程
适用于"发送即忘"的操作,如更新窗口标题。
API 组合:ipcRenderer.send + ipcMain.on

3.1.1 主进程 - main.js
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("path");
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
});
win.loadFile("index.html");
win.webContents.openDevTools(); // 开发时打开调试工具
return win;
};
app.on("ready", () => {
// 监听 set-title 事件(渲染进程 → 主进程)
ipcMain.on("set-title", (event, title) => {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
win.setTitle(title);
});
createWindow();
});
3.1.2 预加载脚本 - preload.js
const { contextBridge, ipcRenderer } = require("electron");
// 暴露版本信息到渲染进程
contextBridge.exposeInMainWorld("versions", {
node: process.versions.node,
chrome: process.versions.chrome,
electron: process.versions.electron,
});
// 暴露 IPC 通信接口
contextBridge.exposeInMainWorld("electron", {
setTitle: (title) => ipcRenderer.send("set-title", title),
});
3.1.3 渲染进程 - index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Hello World</h1>
<h1 id="info">info:</h1>
<input type="text" id="titleInput"/>
<button id="btn">修改标题</button>
<script src="./renderer.js"></script>
</body>
</html>
3.1.4 渲染进程 - renderer.js
const info = document.getElementById("info");
info.innerHTML = `Chrome (v${window.versions.chrome}), Node.js (v${window.versions.node}), Electron (v${window.versions.electron})`;
const btn = document.getElementById("btn");
const titleInput = document.getElementById("titleInput");
btn.addEventListener("click", () => {
const title = titleInput.value;
window.electron.setTitle(title);
});
3.2 双向通信:渲染进程 ↔ 主进程
适用于需要等待返回结果的异步操作,如文件读写。
API 组合:ipcRenderer.invoke + ipcMain.handle

3.2.1 修改 index.html
<body>
<h1>Hello World</h1>
<h1 id="info">info:</h1>
<input type="text" id="titleInput"/>
<button id="btn">修改标题</button>
文件内容:<input id="content"/>
<button id="btnFile" type="button">写入文件</button>
<div id="fileInfo"></div>
</body>
3.2.2 修改 preload.js
contextBridge.exposeInMainWorld("electron", {
setTitle: (title) => ipcRenderer.send("set-title", title),
// 双向通信:返回 Promise
writeFile: (content) => ipcRenderer.invoke("write-file", content),
});
3.2.3 修改 renderer.js
const btnFile = document.getElementById("btnFile");
const contentInput = document.getElementById("content");
btnFile.addEventListener("click", async () => {
const content = contentInput.value;
const len = await window.electron.writeFile(content);
const fileInfo = document.getElementById("fileInfo");
fileInfo.innerHTML = `文件写入成功,文件大小为 ${len} 字节`;
});
3.2.4 修改 main.js
const fs = require("fs");
app.on("ready", () => {
// ... 其他代码
// 处理 write-file 事件,返回值会作为 Promise 返回给渲染进程
ipcMain.handle("write-file", async (event, content) => {
await fs.promises.writeFile("test.txt", content);
const stats = await fs.promises.stat("test.txt");
return stats.size;
});
createWindow();
});
3.3 单向通信:主进程 → 渲染进程
适用于主进程主动推送数据,如定时更新、系统通知。
API 组合:webContents.send + ipcRenderer.on

3.3.1 修改 index.html
<body>
<h1>Hello World</h1>
<h1 id="info">info:</h1>
<input type="text" id="titleInput"/>
<button id="btn">修改标题</button>
文件内容:<input id="content"/>
<button id="btnFile" type="button">写入文件</button>
<div id="fileInfo"></div>
<h1 id="counter"></h1>
</body>
3.3.2 修改 preload.js
contextBridge.exposeInMainWorld("electron", {
setTitle: (title) => ipcRenderer.send("set-title", title),
writeFile: (content) => ipcRenderer.invoke("write-file", content),
// 主进程 → 渲染进程:注册监听器
onUpdateCounter: (callback) =>
ipcRenderer.on("update-counter", (event, value) => {
callback(value);
}),
});
3.3.3 修改 renderer.js
// 监听主进程推送的计数器更新
const counter = document.getElementById("counter");
window.electron.onUpdateCounter((value) => {
counter.innerText = `counter:${value}`;
});
3.3.4 修改 main.js
app.on("ready", () => {
// ... 其他代码
const mainWindow = createWindow();
let counter = 1;
// 等待页面加载完成后再发送消息
mainWindow.webContents.on("did-finish-load", () => {
mainWindow.webContents.send("update-counter", counter);
// 每 3 秒更新一次计数器
setInterval(() => {
counter += 3;
mainWindow.webContents.send("update-counter", counter);
}, 3000);
});
});
3.3.5 关键要点
-
发送消息:使用
win.webContents.send(channel, data) -
接收消息:在 preload.js 中用
ipcRenderer.on(channel, callback)接收并暴露给渲染进程 -
生命周期:必须等待
did-finish-load事件,确保渲染进程已准备好 -
安全实践:通过 preload 脚本暴露接口,避免直接在渲染进程访问
ipcRenderer
3.3.6 常见页面生命周期事件
// 页面开始加载
mainWindow.webContents.on('did-start-loading', () => {});
// 开始导航
mainWindow.webContents.on('did-start-navigation', () => {});
// DOM 准备就绪(类似 DOMContentLoaded)
mainWindow.webContents.on('dom-ready', () => {});
// 页面完全加载完成(推荐)
mainWindow.webContents.on('did-finish-load', () => {
// 此时可安全发送消息到渲染进程
});
// 停止加载
mainWindow.webContents.on('did-stop-loading', () => {});
3.4 IPC 通信总结
| 通信方向 | 渲染进程 API | 主进程 API | 使用场景 |
|---|---|---|---|
| 渲染 → 主 | ipcRenderer.send |
ipcMain.on |
单向通知(不需要返回值) |
| 渲染 ↔ 主 | ipcRenderer.invoke |
ipcMain.handle |
请求-响应(需要返回值) |
| 主 → 渲染 | ipcRenderer.on |
webContents.send |
主进程推送数据 |
4. 安全机制:沙盒模式
Electron 通过沙盒模式限制渲染进程对系统资源的访问,以减少安全风险。沙盒化应用于主进程以外的大多数进程,包括渲染进程和功能性进程(如音频服务、GPU 服务、网络服务)。
核心原则: 渲染进程在受限环境中运行,需要额外权限的操作通过 IPC 委托给主进程执行。
默认安全状态: 现代 Electron(20+)默认启用了完整的沙盒安全配置(nodeIntegration: false、contextIsolation: true、sandbox: true、webSecurity: true),开发者通常无需手动配置这些选项。以下配置项说明仅供理解安全机制使用。
正确的开发模式: 在默认的沙盒模式(sandbox: true)下,预加载脚本和渲染进程都无法直接访问 Node.js API。正常的交互逻辑应该通过以下方式实现:
-
预加载脚本(preload.js):在沙盒模式下只能访问 Electron 渲染进程 API(如
ipcRenderer、contextBridge),不能访问 Node.js API -
IPC 通信:预加载脚本通过
contextBridge向渲染进程暴露安全的 API 接口 - 主进程处理:需要系统级权限的操作(如文件读写、系统调用)在主进程中执行,通过 IPC 返回结果
这种模式确保了应用的安全性,同时提供了必要的系统功能访问能力。
比如,在preload.js,修改如下:
const { contextBridge, ipcRenderer } = require("electron");
const fs = require("fs");
console.log(fs);
......
运行会报错:

4.1 关键安全配置项
沙盒模式由多个配置项共同控制,默认配置已经是安全的,通常不需要修改:
4.1.1 nodeIntegration(Node.js 集成)
控制渲染进程是否可以直接访问 Node.js API。
安全配置(推荐)
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: false, // ✅ 渲染进程无法直接使用 Node.js API
preload: path.join(__dirname, "preload.js")
}
});
- 渲染进程无法直接访问
require、fs等 Node.js API - 必须通过 preload 脚本的
contextBridge暴露接口 - 适用于生产环境
不安全配置(不推荐)
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true, // ❌ 渲染进程可直接使用 Node.js
contextIsolation: false // 必须同时关闭
}
});
- 渲染进程可直接使用
require('fs')、require('path')等 - 无需 preload 脚本,但存在严重安全风险
- 如果加载不受信任的远程内容,可能导致任意代码执行
// 示例:渲染进程直接使用 Node.js(不安全)
const fs = require('fs');
fs.readFileSync('file.txt', 'utf-8');
4.1.2 contextIsolation(上下文隔离)
隔离 preload 脚本和渲染进程的 JavaScript 上下文。
const win = new BrowserWindow({
webPreferences: {
contextIsolation: true, // ✅ 默认值,preload 和渲染进程上下文隔离
}
});
-
true(默认):preload 脚本和网页代码运行在不同的上下文,必须通过contextBridge通信 -
false:共享全局对象,网页可直接访问 preload 中的变量(不安全)
4.1.3 sandbox(系统级沙盒)
启用操作系统级别的沙盒保护。
const win = new BrowserWindow({
webPreferences: {
sandbox: true, // ✅ 启用系统级沙盒
}
});
- 限制渲染进程的系统调用能力
- 即使渲染进程被攻破,也难以影响操作系统
4.1.4 webSecurity(Web 安全策略)
控制是否启用同源策略等 Web 安全机制。
const win = new BrowserWindow({
webPreferences: {
webSecurity: true, // ✅ 默认值,启用同源策略
}
});
4.2 完整的安全配置示例
const { app, BrowserWindow } = require('electron');
const path = require('path');
const createSecureWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 核心安全配置
nodeIntegration: false, // 禁止渲染进程直接访问 Node.js
contextIsolation: true, // 隔离 preload 和渲染进程上下文
sandbox: true, // 启用操作系统级沙盒
webSecurity: true, // 启用 Web 安全策略
// 安全地暴露 API
preload: path.join(__dirname, 'preload.js')
}
});
win.loadFile('index.html');
// 或加载远程内容
// win.loadURL('https://example.com');
return win;
};
app.on('ready', createSecureWindow);
4.3 配置项总结
| 配置项 | 默认值 | 作用 | 建议 |
|---|---|---|---|
nodeIntegration |
false |
控制渲染进程是否可访问 Node.js API | 保持 false
|
contextIsolation |
true |
隔离 preload 和渲染进程上下文 | 保持 true
|
sandbox |
true (Electron 20+) |
启用操作系统级沙盒 | 保持 true
|
webSecurity |
true |
启用同源策略等 Web 安全机制 | 保持 true
|
4.4 沙盒模式 vs iframe 沙盒
4.4.1 相似之处
Electron 沙盒和 Web iframe 沙盒都涉及内容隔离和权限控制:
| 对比维度 | Electron 渲染进程(沙盒) | Web iframe(沙盒) |
|---|---|---|
| 隔离机制 | 进程级隔离 | 同源策略 + 沙盒属性 |
| 权限限制 | 限制访问 Node.js API 和系统资源 | 限制表单提交、脚本执行、弹窗等 |
| 通信方式 | IPC(进程间通信) | postMessage(窗口间通信) |
| 安全目的 | 防止恶意代码访问系统 | 防止恶意代码访问父页面 |
4.4.2 关键区别
隔离级别不同
// Electron:进程级隔离
// 渲染进程和主进程是独立的操作系统进程,崩溃互不影响
const win = new BrowserWindow({
webPreferences: { sandbox: true } // 操作系统级别的沙盒
});
<!-- Web iframe:浏览器沙盒 -->
<!-- 仍在同一个浏览器进程内,只是限制了部分功能 -->
<iframe src="content.html" sandbox="allow-scripts"></iframe>
权限范围不同
- Electron 沙盒:主要限制 Node.js API 和系统资源访问(文件系统、子进程等)
- iframe 沙盒:限制 Web API(表单提交、弹窗、同源访问、脚本执行等)
通信机制不同
// Electron IPC:跨进程通信,可传递复杂数据
// 渲染进程
window.electron.readFile('/path/to/file');
// 主进程
ipcMain.handle('read-file', async (event, filePath) => {
return fs.readFileSync(filePath, 'utf-8');
});
// iframe postMessage:跨窗口通信,只能传递可序列化数据
// 父页面
iframe.contentWindow.postMessage({ type: 'getData' }, '*');
// iframe 内
window.addEventListener('message', (event) => {
if (event.data.type === 'getData') {
event.source.postMessage({ result: 'data' }, event.origin);
}
});
使用场景不同
- Electron 沙盒:适用于需要加载第三方 Web 内容但又要访问系统功能的桌面应用
- iframe 沙盒:适用于 Web 应用中嵌入不受信任的第三方内容
4.4.3 实际示例对比
Electron 场景:嵌入不受信任的网页
// 加载外部网站,但仍想在应用内控制
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: false, // 禁止访问 Node.js
contextIsolation: true, // 隔离上下文
sandbox: true, // 启用沙盒
webSecurity: true // 启用 Web 安全策略
}
});
win.loadURL('https://untrusted-site.com');
Web iframe 场景:嵌入第三方组件
<!-- 嵌入第三方广告或小部件 -->
<iframe
src="https://ads.example.com/banner"
sandbox="allow-scripts allow-same-origin"
style="width: 300px; height: 250px;">
</iframe>
4.4.4 总结
- 概念相似:都是通过隔离和权限限制提升安全性
- 实现不同:Electron 是操作系统级进程隔离,iframe 是浏览器内的功能隔离
- 应用场景:Electron 关注系统资源保护,iframe 关注 Web 内容隔离
-
推荐实践:Electron 默认配置(
nodeIntegration: false)+ preload 脚本是最安全的方案