From 7f3f4d3914269cbe7c173fc6eea29f74a1d0e5b1 Mon Sep 17 00:00:00 2001 From: thzxx Date: Wed, 10 Jun 2026 16:22:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BB=A3=E7=90=86=E6=94=B9=E7=94=A8=20h?= =?UTF-8?q?ttps.request+HttpsProxyAgent=20=E7=9B=B4=E8=BF=9E=EF=BC=8C?= =?UTF-8?q?=E7=BB=95=E8=BF=87=20undici=20fetch=20=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/tool-handlers-system.ts | 60 +++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/main/tool-handlers-system.ts b/src/main/tool-handlers-system.ts index c27a9fa..3705d03 100644 --- a/src/main/tool-handlers-system.ts +++ b/src/main/tool-handlers-system.ts @@ -207,30 +207,48 @@ function buildFetchHeaders(url: string, useMobileUA: boolean): Record): Promise { const _headers = headers || buildFetchHeaders(url, false); - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeout); - try { - const agent = getProxyAgent(); - const fetchOpts: any = { - headers: _headers, - signal: controller.signal, - redirect: 'follow', - }; - if (agent) fetchOpts.dispatcher = agent; - const resp = await fetch(url, fetchOpts); - clearTimeout(timeoutId); - return resp; - } catch (err) { - clearTimeout(timeoutId); - if (_proxyUrl) { - const msg = (err as Error).message || ''; - sendLog('warn', `🌐 fetch 失败`, `${url.slice(0, 80)} | 代理=${_proxyUrl} | ${msg.slice(0, 100)}`); - } - return null; + + // 有代理时用 https.request(兼容 https-proxy-agent) + const proxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || ''; + if (proxy) { + try { + const { HttpsProxyAgent } = require('https-proxy-agent'); + return new Promise((resolve) => { + const mod = require(url.startsWith('https:') ? 'https' : 'http'); + const u = new URL(url); + const req = mod.request({ + hostname: u.hostname, port: u.port || (url.startsWith('https:') ? 443 : 80), + path: u.pathname + u.search, method: 'GET', + headers: { ..._headers, Host: u.hostname }, + agent: new HttpsProxyAgent(proxy), timeout, rejectUnauthorized: false, + }, (res: any) => { + let body = ''; + res.on('data', (d: Buffer) => body += d.toString()); + res.on('end', () => resolve({ + ok: res.statusCode >= 200 && res.statusCode < 400, + status: res.statusCode, statusText: res.statusMessage, + headers: new Headers(res.headers as Record), + text: () => Promise.resolve(body), + arrayBuffer: () => Promise.resolve(Buffer.from(body).buffer), + } as unknown as Response)); + }); + req.on('timeout', () => req.destroy()); + req.on('error', (e: Error) => { sendLog('warn', `🌐 代理请求失败`, `${url.slice(0,80)} | ${e.message.slice(0,100)}`); resolve(null); }); + req.end(); + }); + } catch { /* 代理包不可用,回退到原生 fetch */ } } + + // 无代理 / 代理包不可用 → 原生 fetch + const controller = new AbortController(); + const tid = setTimeout(() => controller.abort(), timeout); + try { + const resp = await fetch(url, { headers: _headers, signal: controller.signal, redirect: 'follow' }); + clearTimeout(tid); return resp; + } catch { clearTimeout(tid); return null; } } /** 完整 HTML 实体映射(常见实体) */