人人都会AI编程

13.1 网络请求方案:渲染端 fetch/axios、主进程 net 模块

更新时间:2026-07-11

在 Electron 应用中发起网络请求,不像传统 Web 应用只有浏览器环境这一种选择。你可以继续在渲染进程里使用熟悉的 fetchaxios,也可以将网络请求放到主进程,通过 Node.js 的 http/https 模块甚至 Electron 特有的 net 模块来完成。这一节会把这些方案的适用场景、写法和需要注意的坑都讲清楚。

13.1.1 在渲染进程使用 fetch 和 axios

最省事的方案:直接用浏览器 API

Electron 的渲染进程本质上就是一个 Chromium 浏览器,所以你在里面使用 window.fetchXMLHttpRequest、或者基于前两者封装的 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 模块类似,但有两个突出优点:

  1. 复用 Chromium 的网络配置:它能直接使用系统代理设置、SSL 证书管理、session 中的 cookie 和缓存,和渲染进程的请求共享同一套网络状态。
  2. 与浏览器行为一致:例如发出的请求会自动带上 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 实际开发中的建议

  1. 默认先用渲染进程的 fetch/axios。开发快,调试方便,浏览器 DevTools 能直接看到请求详情,除非遇到必须隐藏凭据或需要后台上传/下载的情况,再挪到主进程。
  2. 统一错误处理与超时。无论是 fetch 还是 net.request,都要设置合理的超时,否则可能因为网络丢包导致应用卡死。axios 自带超时配置,fetch 可以包装 AbortController,net.request 可以用 setTimeout 搭配 abort()
  3. 避免跨域策略的“硬关闭”。尽量不要图方便把 webSecurity 设为 false,而是在主进程通过 session.defaultSession.webRequest 添加必要的响应头,或者直接让服务端允许目标来源。
  4. 注意 HTTPS 证书校验。在生产环境务必保持浏览器默认的安全策略,仅对开发环境做放宽。

综合来看,Electron 为你提供了一套灵活的网络请求工具链:渲染进程让你保持 Web 开发的惯性,主进程的 net 模块让你在享受 Chromium 网络栈便利的同时,还能兼顾安全与后台任务。根据具体需求选择最合适的路径,就能在不增加太多复杂度的前提下,将网络请求处理得既快又稳。