mirror of
https://github.com/foxhui/WebAI2API.git
synced 2026-06-16 21:03:59 +08:00
fix: 修复无需鉴权的 Socks5 代理无法使用的问题
This commit is contained in:
@@ -317,12 +317,12 @@ export const manifest = {
|
||||
models: [
|
||||
{ id: 'gemini-3-pro', codeName: 'gemini-3-pro-preview', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-2.5-pro', codeName: 'gemini-2.5pro', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-3-flash-preview', codeName: 'gemini-3-pro-preview', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-3-flash', codeName: 'gemini-3-pro-preview', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-2.5-flash', codeName: 'gemini-2.5-flash', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-3-pro-grounding', codeName: 'gemini-3-pro-preview', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-2.5-pro-grounding', codeName: 'gemini-2.5-pro', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-2.5-flash-grounding', codeName: 'gemini-2.5-flash', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-3-flash-preview-grounding', codeName: 'gemini-3-flash-preview', imagePolicy: 'optional', type: 'text' },
|
||||
{ id: 'gemini-3-flash-grounding', codeName: 'gemini-3-flash-preview', imagePolicy: 'optional', type: 'text' },
|
||||
],
|
||||
|
||||
// 导航处理器
|
||||
|
||||
@@ -226,12 +226,20 @@ async function waitForElementStable(element, stableFrames = 10, timeout = 2000)
|
||||
*/
|
||||
export async function safeClick(page, target, options = {}) {
|
||||
const clickCount = options.clickCount || 1;
|
||||
const timeout = options.timeout || TIMEOUTS.ELEMENT_CLICK;
|
||||
const waitStable = options.waitStable !== false; // 默认 true
|
||||
const selector = typeof target === 'string' ? target : '元素';
|
||||
// humanizeCursorMode: false=禁用, true=ghost-cursor, "camou"=Camoufox内置
|
||||
// 只有 true 时才使用 ghost-cursor,其他情况都使用原生点击
|
||||
const useGhostCursor = page?._humanizeCursorMode === true && page?.cursor;
|
||||
const cursorSpeed = options.cursorSpeed ?? 40;
|
||||
|
||||
// 动态计算超时时间:使用 ghost-cursor 时,速度越慢超时越长
|
||||
// 公式:基础超时 + 额外时间(50000ms / 速度)
|
||||
// 速度40时额外1.25s,速度10时额外5s,速度5时额外10s
|
||||
const baseTimeout = options.timeout || TIMEOUTS.ELEMENT_CLICK;
|
||||
const timeout = useGhostCursor
|
||||
? baseTimeout + Math.ceil(50000 / cursorSpeed)
|
||||
: baseTimeout;
|
||||
|
||||
const doClick = async () => {
|
||||
let el;
|
||||
@@ -270,7 +278,6 @@ export async function safeClick(page, target, options = {}) {
|
||||
if (box) {
|
||||
const { x, y } = getHumanClickPoint(box, options.bias || 'random');
|
||||
logger.debug('浏览器', `[safeClick] 移动鼠标到 (${x.toFixed(0)}, ${y.toFixed(0)})...`);
|
||||
const cursorSpeed = options.cursorSpeed ?? 40;
|
||||
await page.cursor.moveTo({ x, y }, { moveSpeed: cursorSpeed });
|
||||
logger.debug('浏览器', `[safeClick] 执行点击...`);
|
||||
await page.mouse.click(x, y, { clickCount });
|
||||
|
||||
@@ -91,9 +91,9 @@ export class Worker {
|
||||
|
||||
logger.info('工作池', `[${this.name}] 正在初始化浏览器...`);
|
||||
if (this.proxyConfig) {
|
||||
logger.debug('工作池', `[${this.name}] 使用代理: ${this.proxyConfig.type}://${this.proxyConfig.host}:${this.proxyConfig.port}`);
|
||||
logger.info('工作池', `[${this.name}] 使用代理: ${this.proxyConfig.type}://${this.proxyConfig.host}:${this.proxyConfig.port}`);
|
||||
} else {
|
||||
logger.debug('工作池', `[${this.name}] 直连模式(无代理)`);
|
||||
logger.info('工作池', `[${this.name}] 直连模式(无代理)`);
|
||||
}
|
||||
|
||||
if (sharedBrowser) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import path from 'path';
|
||||
import os from 'os';
|
||||
import crypto from 'crypto';
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { CAMOUFOX_PATCHES } from '../../scripts/postinstall.js';
|
||||
|
||||
const PROJECT_ROOT = process.cwd();
|
||||
|
||||
@@ -53,16 +54,11 @@ export function preflight() {
|
||||
errors.push('better-sqlite3 预编译文件缺失,请运行: npm run init');
|
||||
}
|
||||
|
||||
// 2. 检查 camoufox-js 补丁(通过 MD5 对比)
|
||||
// 2. 检查 camoufox-js 补丁(通过 MD5 对比,使用 postinstall.js 导出的补丁列表)
|
||||
const patchDir = path.join(PROJECT_ROOT, 'patches');
|
||||
const targetDir = path.join(PROJECT_ROOT, 'node_modules', 'camoufox-js', 'dist');
|
||||
|
||||
const patchFiles = {
|
||||
'camoufox-js@0.8.3.locale.patched.js': 'locale.js',
|
||||
'camoufox-js@0.8.3.pkgman.patched.js': 'pkgman.js'
|
||||
};
|
||||
|
||||
for (const [patchName, targetName] of Object.entries(patchFiles)) {
|
||||
for (const [patchName, targetName] of Object.entries(CAMOUFOX_PATCHES)) {
|
||||
const patchPath = path.join(patchDir, patchName);
|
||||
const targetPath = path.join(targetDir, targetName);
|
||||
|
||||
|
||||
+17
-34
@@ -94,44 +94,27 @@ export async function getBrowserProxy(proxyConfig) {
|
||||
|
||||
const { type, host, port, user, passwd } = proxyConfig;
|
||||
|
||||
// 对于 SOCKS5 + 认证,需要转换为 HTTP 代理
|
||||
if (type === 'socks5' && user && passwd) {
|
||||
try {
|
||||
const originalUrl = buildProxyUrl(proxyConfig);
|
||||
logger.info('代理器', `检测到需鉴权的 SOCKS5 代理,正在创建本地代理桥接: ${host}:${port}`);
|
||||
|
||||
const httpProxyUrl = await anonymizeProxy(originalUrl);
|
||||
|
||||
// 保存状态用于后续清理
|
||||
proxyState.anonymizedProxyUrl = httpProxyUrl;
|
||||
proxyState.originalProxyUrl = originalUrl;
|
||||
|
||||
logger.info('代理器', `本地代理桥接已建立: ${httpProxyUrl} -> ${host}:${port}`);
|
||||
|
||||
return {
|
||||
server: httpProxyUrl
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('代理器', `本地代理桥接创建失败: ${error.message}`);
|
||||
throw error;
|
||||
// 构建代理 URL 字符串
|
||||
// 注意:Camoufox 对 socks5:// 协议使用 new URL().origin 会返回 null
|
||||
// 因此我们直接返回完整的 URL 字符串,让 Camoufox 使用 new URL().href
|
||||
let proxyUrl;
|
||||
if (user && passwd) {
|
||||
// 带认证的代理格式: protocol://user:passwd@host:port
|
||||
const protocol = type === 'socks5' ? 'socks5' : 'http';
|
||||
proxyUrl = `${protocol}://${encodeURIComponent(user)}:${encodeURIComponent(passwd)}@${host}:${port}`;
|
||||
} else {
|
||||
// 不带认证的代理格式: protocol://host:port
|
||||
if (type === 'socks5') {
|
||||
proxyUrl = `socks5://${host}:${port}`;
|
||||
} else {
|
||||
proxyUrl = `http://${host}:${port}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 对于其他情况(HTTP 代理、不带认证的 SOCKS5)
|
||||
const proxyUrl = type === 'socks5' ? `socks5://${host}:${port}` : `${host}:${port}`;
|
||||
logger.info('代理器', `代理配置: ${type}://${host}:${port}${user ? ' (带认证)' : ''}`);
|
||||
|
||||
const proxyObject = {
|
||||
server: proxyUrl
|
||||
};
|
||||
|
||||
// 如果有认证信息,添加到代理对象
|
||||
if (user && passwd) {
|
||||
proxyObject.username = user;
|
||||
proxyObject.password = passwd;
|
||||
}
|
||||
|
||||
logger.info('代理器', `代理配置: ${type}://${host}:${port}`);
|
||||
return proxyObject;
|
||||
// 直接返回字符串格式,Camoufox 会正确解析
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user