Electron v21升级后net.request周期性无法获取响应头求助
问题背景
我需要连接服务器(如https://myserver/file.exe)检查文件新版本并执行更新,原本通过@electron/remote的net模块发起请求,从response.headers中获取last-modified头参数判断版本。
该功能在Electron 12.2.2中正常运行,但升级到v21.0.1后,频繁出现请求返回200状态码和数据,但响应头为空的情况,日志示例:
STATUS: 200
HEADERS: {}
data: Array(15)
仅约10%的请求能正常获取完整响应头,示例:
HEADERS: {"date":"Wed, 05 Oct 2022 12:22:42 GMT","etag":""633bc02a-aec01d"","last-modified":"Tue, 04 Oct 2022 05:10:02 GMT","cache-control":"max-age=3600","cf-cache-status":"REVALIDATED","report-to":"{"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v3?s=CkyxJliNOH9rDYgSVpjID7NaTVlUkBH1tgJxibvzmTh%2BRpZBk0FeFf03oJuHateoQVnWJhqSn1FHNs2%2FB%2Fkc%2BDuiaAnt%2BKHmzRlGoAY%2BGDplpVJ1K%2BXVDITGmD0xeFRXtA%3D%3D"}],"group":"cf-nel","max_age":604800}","nel":"{"success_fraction":0,"report_to":"cf-nel","max_age":604800}","vary":"Accept-Encoding","server":"cloudflare","cf-ray":"75561fd10c439b3d-FRA","alt-svc":"h3=":443"; ma=86400, h3-29=":443"; ma=86400"}
注:请求经过Cloudflare代理,用Postman发起相同请求始终能正常获取响应头。此问题导致无法依赖last-modified判断更新,完全破坏了更新逻辑,希望在不降级Electron的前提下找到原因和解决办法。
当前代码
const { net } = require('@electron/remote'); ... checkUpdate() { const request = net.request({ method: 'GET', protocol: 'https:', hostname: <myUrl>, port: 443, path: <myPath> }); request.setHeader('x-abs-abcore-version', '1.00'); request.setHeader('x-abs-abcore-type', 'crossplatform'); request.setHeader('Content-Type', 'application/x-www-form-urlencoded'); request.on('response', (response) => { const data = []; response.on('error', (e) => { console.log(e); }); response.on('data', (chunk) => { data.push(chunk) }); response.on('end', () => { console.log(`STATUS: ${response.statusCode}`) console.log(`HEADERS: ${JSON.stringify(response.headers)}`) console.log("data",data) if (Date.parse(<localFilesLastModified>) < Date.parse(response.headers['last-modified'].toString())) { //Do some update } }); request.on('error', (err) => { console.log(err) }); request.end(); }); }
可能原因与解决方案
1. 移除@electron/remote依赖,直接使用主进程的net模块
Electron从v14开始逐步弱化remote模块,v20+更是将其标记为废弃,使用remote的net可能存在兼容性问题。建议将请求逻辑移到主进程,通过IPC与渲染进程通信:
主进程代码示例:
const { net, ipcMain } = require('electron'); ipcMain.handle('check-update', async () => { return new Promise((resolve, reject) => { const request = net.request({ method: 'GET', protocol: 'https:', hostname: <myUrl>, port: 443, path: <myPath> }); request.setHeader('x-abs-abcore-version', '1.00'); request.setHeader('x-abs-abcore-type', 'crossplatform'); // GET请求无需设置Content-Type,可移除该行 // request.setHeader('Content-Type', 'application/x-www-form-urlencoded'); request.on('response', (response) => { const headers = response.headers; const data = []; response.on('data', (chunk) => data.push(chunk)); response.on('end', () => resolve({ statusCode: response.statusCode, headers, data })); response.on('error', reject); }); request.on('error', reject); request.end(); }); });
渲染进程代码示例:
const { ipcRenderer } = require('electron'); async function checkUpdate() { try { const { statusCode, headers, data } = await ipcRenderer.invoke('check-update'); console.log(`STATUS: ${statusCode}`); console.log(`HEADERS: ${JSON.stringify(headers)}`); if (headers['last-modified'] && Date.parse(<localFilesLastModified>) < Date.parse(headers['last-modified'])) { // 执行更新逻辑 } } catch (err) { console.error(err); } }
2. 修复冗余的请求头设置
当前代码为GET请求设置了Content-Type: application/x-www-form-urlencoded,这是不必要的,可能导致Cloudflare或服务器的异常处理,建议直接移除该行。
3. 禁用HTTP/3,强制使用HTTP/1.1或HTTP/2
Electron v21默认启用了HTTP/3支持,部分CDN(如Cloudflare)在HTTP/3下的响应头处理可能存在兼容性问题,可以强制关闭HTTP/3:
const { session } = require('electron'); const request = net.request({ // ...其他配置 session: session.fromPartition('no-http3', { network: { enableHttp3: false } }) });
4. 提前获取响应头,避免在end事件中读取
尝试在response回调中直接获取响应头,或监听headers事件,避免在end事件中可能出现的头丢失:
request.on('response', (response) => { // 直接在响应回调里获取headers console.log('HEADERS:', response.headers); // 或监听headers事件 response.on('headers', (headers) => { console.log('HEADERS EVENT:', headers); }); // ...其他逻辑 });
内容的提问来源于stack exchange,提问作者Gary Klasen

