在 Electron 应用中发起网络请求,不像传统 Web 应用只有浏览器环境这一种选择。你可以继续在渲染进程里使用熟悉的 fetch 或 axios,也可以将网络请求放到主进程,通过 Node.js 的 http/https 模块甚至 Electron 特有的 net 模块来完成。这一节会把这些方案的适用场景、写法和需要注意的坑都讲清楚。
13.1.1 在渲染进程使用 fetch 和 axios
最省事的方案:直接用浏览器 API
Electron 的渲染进程本质上就是一个 Chromium 浏览器,所以你在里面使用 window.fetch、XMLHttpRequest、或者基于前两者封装的 axios,都和写普通网页完全一样。
// 渲染进程 renderer.js
async function loadUserData() {
try {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('请求失败', error);
}
}
同样,axios 的用法不需要任何额外配置:
import axios from 'axios';
const { data } = await axios.get('https://api.example.com/user');
跨域问题会自动消失
在传统浏览器中,向不同域名发送请求会受同源策略限制,你必须去服务器端配置 CORS 响应头。而在 Electron 的渲染进程中,你可以主动控制这一行为:通过 webPreferences.webSecurity 关闭同源检查(不推荐),或者更优雅地在主进程通过 webRequest 会话模块接口修改请求头。
但在绝大多数场景,你根本不需要处理跨域 —— 因为 Electron 允许你在创建窗口时设置 webSecurity: false(仅用于本地文件和可信内容),或者通过定制 ses 会话补上缺少的 CORS 头。如果你只是为了访问几个已知的 API,最直接的办法是在后端 API 中添加 CORS 支持,这和传统 Web 开发完全一样。
一个小陷阱:HTTPS 证书错误
开发时如果访问的是自签名 HTTPS 的测试服务器,Electron 会像浏览器一样阻止请求。你可以在主进程监听 certificate-error 事件在已知的域名上忽略证书错误:
// 主进程
const { app } = require('electron');
app.on('certificate-error', (event, _webContents, url, _error, _certificate, callback) => {
if (url.startsWith('https://your-test-server.com')) {
event.preventDefault();
callback(true); // 信任该证书
} else {
callback(false);
}
});
生产环境务必去掉这类全局忽略,只针对特定开发服务器使用。
适合用渲染进程发请求的场景
- 前端代码需要直接消费数据(例如更新 UI 状态、提交表单)。
- 不需要隐藏 API 地址或 cookie 等敏感信息。
- 请求结果直接驱动界面更新,一次来回,链路最短。
13.1.2 在主进程使用 net 模块
Electron 的 net 模块是 Chromium 网络栈的 Node.js 封装版。它和 Node.js 的 http/https 模块类似,但有两个突出优点:
- 复用 Chromium 的网络配置:它能直接使用系统代理设置、SSL 证书管理、session 中的 cookie 和缓存,和渲染进程的请求共享同一套网络状态。
- 与浏览器行为一致:例如发出的请求会自动带上 Electron 会话中的 cookie,不需要单独维护 cookie jar。
基本用法
// 主进程 main.js
const { app, net } = require('electron');
// 发起一个 GET 请求
const request = net.request({
method: 'GET',
url: 'https://api.example.com/data',
});
request.on('response', (response) => {
console.log(`状态码: ${response.statusCode}`);
response.on('data', (chunk) => {
// 数据块
console.log('收到数据块:', chunk.toString());
});
response.on('end', () => {
console.log('请求完成');
});
});
request.on('error', (error) => {
console.error('请求失败:', error);
});
request.end();
如果你更喜欢 Promise 风格,可以手写一个简单的封装:
function netRequest(options) {
return new Promise((resolve, reject) => {
const request = net.request(options);
let data = '';
request.on('response', (response) => {
response.on('data', (chunk) => {
data += chunk.toString();
});
response.on('end', () => {
resolve({
status: response.statusCode,
headers: response.headers,
body: data,
});
});
});
request.on('error', reject);
if (options.body) {
request.write(options.body);
}
request.end();
});
}
// 使用
const { body } = await netRequest({ method: 'GET', url: 'https://api.example.com/data' });
与 Node.js http 模块的区别
- Node.js 的
http模块不感知 Electron 的会话、代理和证书设置,只能发送“独立”的请求,需要自己管理 cookie、代理等。 net模块完全基于 Chromium 的网络栈,使得主进程发出的请求和渲染进程的请求共享登录状态,这对需要统一身份认证的应用特别实用。
适合用主进程发请求的场景
- 需要在后台静默同步数据(不依赖于窗口的渲染进程)。
- 需要隐藏真实的 API 地址或避免将 token 暴露给渲染进程(安全考量)。
- 请求的结果需要与系统能力联动,例如下载文件、调用系统命令行处理返回的数据。
- 希望所有请求都统一走 Electron 的 session,以复用登录凭据。
13.1.3 渲染进程与主进程的网络请求配合
在真实项目中,往往不是非此即彼,而是混合使用。常见的模式是:
- 在渲染进程直接使用
fetch请求常规数据、加载图片、上传小文件。 - 对于需要写本地文件、处理大文件流、或需要隐藏 token 的请求,先由渲染进程通过 IPC 通知主进程,由主进程使用
net模块发出请求,再把结果转发回界面。
示例:安全地上传文件
// 预加载 preload.js
contextBridge.exposeInMainWorld('api', {
uploadFile: (filePath) => ipcRenderer.invoke('upload-file', filePath),
});
// 主进程 main.js
const { ipcMain, net } = require('electron');
const fs = require('fs');
ipcMain.handle('upload-file', async (event, filePath) => {
const fileStream = fs.createReadStream(filePath);
const request = net.request({
method: 'POST',
url: 'https://api.example.com/upload',
});
fileStream.pipe(request); // 直接将文件流作为请求体
return new Promise((resolve, reject) => {
request.on('response', (response) => {
let data = '';
response.on('data', (chunk) => { data += chunk; });
response.on('end', () => resolve(data));
});
request.on('error', reject);
});
});
这样渲染进程获取不到服务端上传凭据,主进程可以安全地持有秘钥或 session cookie。
13.1.4 实际开发中的建议
- 默认先用渲染进程的 fetch/axios。开发快,调试方便,浏览器 DevTools 能直接看到请求详情,除非遇到必须隐藏凭据或需要后台上传/下载的情况,再挪到主进程。
- 统一错误处理与超时。无论是
fetch还是net.request,都要设置合理的超时,否则可能因为网络丢包导致应用卡死。axios自带超时配置,fetch可以包装 AbortController,net.request可以用setTimeout搭配abort()。 - 避免跨域策略的“硬关闭”。尽量不要图方便把
webSecurity设为 false,而是在主进程通过session.defaultSession.webRequest添加必要的响应头,或者直接让服务端允许目标来源。 - 注意 HTTPS 证书校验。在生产环境务必保持浏览器默认的安全策略,仅对开发环境做放宽。
综合来看,Electron 为你提供了一套灵活的网络请求工具链:渲染进程让你保持 Web 开发的惯性,主进程的 net 模块让你在享受 Chromium 网络栈便利的同时,还能兼顾安全与后台任务。根据具体需求选择最合适的路径,就能在不增加太多复杂度的前提下,将网络请求处理得既快又稳。