Electron 网络与外部通信

net 模块、fetch、WebSocket、代理、拦截请求与跨域。

Intermediate
Key Points渲染进程里就是浏览器环境,受 CORS 限制;主进程的 net 模块不受同源策略约束。

两种网络栈

WhereAPICORSCookie
Rendererfetch / XMLHttpRequest受限自动带上
Mainnet / net.fetch不受限需手动处理
JavaScript
// 渲染进程:普通 fetch,受 CORS 约束
const r = await fetch('https://api.example.com/data');
const data = await r.json();
JavaScript
// 主进程:net 走 Chromium 的网络栈,但不受同源策略限制
const { net } = require('electron');

const res = await net.fetch('https://api.example.com/data');
const data = await res.json();

When a third-party API trips CORS, the clean fix is to make the request in the main process and pass the result over IPC. Never disable webSecurity — that removes same-origin protection entirely.

用 IPC 代理请求

JavaScript
// main.js
const { ipcMain, net } = require('electron');

ipcMain.handle('api:get', async (_e, url) => {
  const allow = ['https://api.example.com/'];
  if (!allow.some(p => url.startsWith(p))) {
    throw new Error('不允许的域名');
  }
  const res = await net.fetch(url, { headers: { Accept: 'application/json' } });
  return { status: res.status, body: await res.text() };
});
JavaScript
// preload.js
contextBridge.exposeInMainWorld('api', {
  get: (url) => ipcRenderer.invoke('api:get', url)
});

The allow-list is mandatory. Without it the page gets an arbitrary-URL fetcher and can hit internal endpoints (SSRF). Permit only the domains you actually need.

WebSocket

JavaScript
const ws = new WebSocket('wss://example.com/live');

ws.addEventListener('open', () => ws.send(JSON.stringify({ type: 'subscribe' })));
ws.addEventListener('message', (e) => console.log(JSON.parse(e.data)));
ws.addEventListener('error', () => console.warn('连接出错'));
ws.addEventListener('close', () => {
  setTimeout(reconnect, 2000);          // 简单退避重连
});

代理

JavaScript
const { session } = require('electron');

// 全局代理
session.defaultSession.setProxy({
  proxyRules: 'http://127.0.0.1:7890',
  proxyBypassRules: '<local>'
});

// 查看当前代理
const cfg = await session.defaultSession.resolveProxy('https://example.com');

Corporate apps often need a proxy. setProxy is per-session, so different windows with different sessions can proxy or connect directly independently.

拦截与修改请求

JavaScript
session.defaultSession.webRequest.onBeforeSendHeaders(
  { urls: ['https://api.example.com/*'] },
  (details, callback) => {
    details.requestHeaders['X-Client'] = 'desktop/1.0';
    callback({ requestHeaders: details.requestHeaders });
  }
);

session.defaultSession.webRequest.onHeadersReceived(
  { urls: ['*://*/*'] },
  (details, callback) => {
    const h = details.responseHeaders;
    delete h['X-Frame-Options'];
    callback({ responseHeaders: h });
  }
);
Rewriting response headers bypasses a lot of protection and moves the app outside real security boundaries. Do it only for domains you fully control, never for every request.

离线检测

JavaScript
// 渲染进程
window.addEventListener('online', () => setStatus('已连接'));
window.addEventListener('offline', () => setStatus('离线,数据将在恢复后同步'));

// 主进程
const { net } = require('electron');
net.isOnline();     // 只代表「有网络接口」,不代表真的能上网

net.isOnline() only means an interface is up; a hotel Wi-Fi needing login still returns true. The reliable check is a lightweight request that must succeed.

Friends & Partners