Skip to content

Electron - 原生 Node 模块

在 Electron 中,你可以完全访问 Node.js 内置模块,允许你直接从桌面应用程序与操作系统、文件系统、网络等进行交互。我们之前探讨了 fs(文件系统)模块。现在让我们看看其他有用的 Node.js 模块。

os 模块提供了与操作系统相关的实用方法和属性。这对于根据用户的环境调整应用程序的行为或外观非常宝贵。

方法/属性描述
os.userInfo([options])返回一个包含当前用户信息(如用户名、用户 ID、组 ID、主目录和默认 shell)的对象。对于个性化设置或用户特定配置很有用。
os.platform()返回一个标识操作系统平台的字符串,例如 'darwin' (macOS)、'win32' (Windows)、'linux'。对于平台特定逻辑至关重要。
os.homedir()返回当前用户主目录的字符串路径。非常适合存储用户特定的应用程序数据或配置。
os.arch()返回一个标识 CPU 架构的字符串,例如 'x64'、'arm64'。可用于提供架构特定的二进制文件或优化。
os.EOL一个定义操作系统特定行结束标记的字符串常量(例如,Linux/macOS 上的 \n,Windows 上的 \r\n)。在写入文本文件时使用此项可确保跨平台兼容性。

要在你的 Electron 应用中显示这些信息,你通常会创建一个主进程文件(main.js)来设置 BrowserWindow,以及一个渲染进程文件(HTML 文件)来显示内容。出于安全考虑,最佳实践是使用预加载脚本和 contextBridge 有选择地将 Node.js 模块暴露给渲染进程。

下面是一个示例。首先,你的 main.js 文件:

const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
// contextIsolation 默认为 true,推荐使用
// nodeIntegration 默认为 false,推荐使用
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});

接下来,在同一目录下创建一个 preload.js 文件:

const { contextBridge } = require('electron');
const os = require('os');
contextBridge.exposeInMainWorld('electronOS', {
getUserInfo: () => os.userInfo(),
getPlatform: () => os.platform(),
getHomedir: () => os.homedir(),
getArch: () => os.arch(),
getEOL: () => os.EOL
});

最后,你的 index.html 文件:

<!DOCTYPE html>
<html>
<head>
<title>OS Module Info</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Operating System Information</h1>
<div id="os-info">Loading...</div>
<script>
const osInfoDiv = document.getElementById('os-info');
try {
const userInfo = window.electronOS.getUserInfo();
const platform = window.electronOS.getPlatform();
const homedir = window.electronOS.getHomedir();
const arch = window.electronOS.getArch();
osInfoDiv.innerHTML =
`User Info: ${JSON.stringify(userInfo, null, 2)}<br><br>` +
`Platform: ${platform}<br>` +
`User Home Directory: ${homedir}<br>` +
`OS Architecture: ${arch}`;
} catch (error) {
osInfoDiv.textContent = 'Error accessing OS information. Make sure preload script is configured correctly.';
console.error('Error accessing OS info via contextBridge:', error);
}
</script>
</body>
</html>

使用以下命令运行你的应用:

$ electron .

应用程序窗口将显示系统信息。例如,在 Linux 系统上,你可能会看到:

User Info: {
"uid": 1000,
"gid": 1000,
"username": "youruser",
"homedir": "/home/youruser",
"shell": "/bin/bash"
}
Platform: linux
User Home Directory: /home/youruser
OS Architecture: x64

(注意:实际输出会因你的操作系统和用户配置而异。)

net 模块提供了一个异步网络 API,用于创建 TCP 服务器和客户端(基于流的 socket)。虽然 Electron 应用通常使用更高级别的协议如 HTTP/HTTPS(通过 fetch API 或 axios 等库)或 WebSockets 进行客户端-服务器通信,但 net 模块对于直接的 TCP socket 编程、点对点连接或与特定网络服务交互很有用。

net 模块的关键方法包括:

方法/类描述
net.createServer([options][, connectionListener])创建一个新的 TCP 服务器。connectionListener 函数会自动设置为监听 'connection' 事件,该事件在新客户端连接时触发。
net.createConnection(options[, connectionListener]) / net.connect(options[, connectionListener])创建一个新的 net.Socket 并发起与指定地址和端口的连接。返回 socket 实例。
net.Server.listen(port[, host][, backlog][, callback])启动服务器,使其在指定的 port 和 host 上监听连接。如果省略 host,服务器将接受来自任意 IPv4/IPv6 地址的连接。
net.Server.close([callback])停止服务器接受新连接。允许现有连接完成。当所有连接都结束时,服务器会触发 'close' 事件。
net.Socket.connect(port[, host][, connectListener])打开指定 socket 实例的连接。如果提供了 port 和 host,socket 将作为 TCP 客户端连接。
net.Socket.write(data[, encoding][, callback])在 socket 上发送数据。
net.Socket.on('data', listener)当从 socket 的另一端接收到数据时触发的事件。

有关详细信息,请参阅 官方 Node.js net 模块文档。

让我们通过一个 Electron 应用作为 TCP 客户端连接到一个简单的 Node.js TCP 服务器的示例来演示。首先,创建 server.js 文件(使用 Node.js 运行,而不是 Electron):

const net = require('net');
const server = net.createServer((connection) => {
console.log('Client Connected');
connection.on('end', () => {
console.log('Client disconnected');
});
connection.on('error', (err) => {
console.error('Connection error:', err.message);
});
connection.write('Hello from TCP Server!\r\n');
// Echo back anything received
connection.pipe(connection);
});
const PORT = 8080;
server.listen(PORT, () => {
console.log(`TCP Server running on port ${PORT}`);
});

使用与 os 模块示例中相同的 main.js 文件(用于设置 BrowserWindow 并加载 index.html)。更新 index.html 以实现 TCP 客户端功能:

<!DOCTYPE html>
<html>
<head>
<title>Net Module Client</title>
<meta charset="UTF-8">
</head>
<body>
<h1>TCP Client</h1>
<div id="status">Connecting...</div>
<pre id="messages"></pre>
<script>
// 重要提示:在渲染进程中直接使用 'require("net")'
// 需要在 BrowserWindow 的 webPreferences 中设置 'nodeIntegration: true'。
// 出于安全原因,通常不推荐这样做。
// 对于生产应用,建议在
// 主进程中执行网络操作,并通过 IPC 和预加载脚本与渲染进程通信。
// 对于此教学示例,我们假设 nodeIntegration 可能已启用,
// 或者此脚本已适配预加载脚本环境。
// 如果使用带有 contextBridge 的预加载脚本,你需要暴露 'net' 功能。
// 示例(概念性代码,假设 'electronNet' 通过 contextBridge 暴露):
// const client = window.electronNet.connect({ port: 8080 });
// 直接用法(需要 nodeIntegration: true 或在支持 Node 的环境中执行):
try {
const net = require('net');
const statusDiv = document.getElementById('status');
const messagesPre = document.getElementById('messages');
const client = net.connect({ port: 8080 }, () => {
console.log('Connection established with server!');
statusDiv.textContent = 'Connected to server!';
client.write('Hello server from Electron client!\r\n');
});
client.on('data', (data) => {
console.log('Data from server:', data.toString());
messagesPre.textContent += data.toString();
// 对于此示例,我们在收到服务器的第一条消息后结束连接。
// client.end();
});
client.on('end', () => {
console.log('Disconnected from server');
statusDiv.textContent = 'Disconnected from server.';
});
client.on('error', (err) => {
console.error('Connection error:', err.message);
statusDiv.textContent = `Connection Error: ${err.message}`;
});
} catch (error) {
document.getElementById('status').textContent =
'Error: Could not load net module. Ensure Node integration is enabled or use a preload script.';
console.error(error);
}
</script>
</body>
</html>

要运行此示例:

  1. 在终端中启动 TCP 服务器:node server.js。
  2. 在终端中(项目目录下)运行 Electron 应用:electron .。

Electron 应用窗口将尝试连接到服务器。如果成功,它将显示“Connected to server!”,然后显示从服务器接收到的任何消息,例如“Hello from TCP Server!”。服务器控制台将记录客户端的连接和断开。

虽然为了简单起见直接在渲染进程中使用了 net 模块,但请记住,对于健壮且安全的应用程序,网络操作通常最好在主进程或实用进程中处理,并通过 IPC 将结果通信给渲染进程。