aaaaa
This commit is contained in:
parent
58b9d72ebe
commit
c7035b0784
6
.env
6
.env
@ -12,3 +12,9 @@ MYSQL_DATABASE=windsurf-auto-register
|
|||||||
|
|
||||||
# CapSolver 验证码识别
|
# CapSolver 验证码识别
|
||||||
CAPSOLVER_API_KEY=CAP-0FCDDA4906E87D9F4FF68EAECD34E320876FBA70E4F30EA1ADCD264EDB15E4BF
|
CAPSOLVER_API_KEY=CAP-0FCDDA4906E87D9F4FF68EAECD34E320876FBA70E4F30EA1ADCD264EDB15E4BF
|
||||||
|
|
||||||
|
# 2Captcha 验证码识别 (支持 Stripe hCaptcha)
|
||||||
|
TWOCAPTCHA_API_KEY=4e6ac0ee29459018fd5e0c454163cd4e
|
||||||
|
|
||||||
|
# YesCaptcha 验证码识别 (优先使用)
|
||||||
|
YESCAPTCHA_API_KEY=a8a04f2e8ceab43cdf3793e2b72bf4d76f4f4a6b81789
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"2captcha-ts": "^2.4.1",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"commander": "^11.0.0",
|
"commander": "^11.0.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
|
|||||||
@ -19,7 +19,9 @@ const { DEFAULT_CONFIG } = require('../config');
|
|||||||
const CardGenerator = require('../../card-generator/generator');
|
const CardGenerator = require('../../card-generator/generator');
|
||||||
const database = require('../../database');
|
const database = require('../../database');
|
||||||
const CapSolverAPI = require('../utils/capsolver-api');
|
const CapSolverAPI = require('../utils/capsolver-api');
|
||||||
|
const YesCaptchaAPI = require('../utils/yescaptcha-api');
|
||||||
const BrowserManager = require('../utils/browser-manager');
|
const BrowserManager = require('../utils/browser-manager');
|
||||||
|
const { Solver } = require('2captcha-ts');
|
||||||
|
|
||||||
class WindsurfRegister {
|
class WindsurfRegister {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
@ -29,6 +31,23 @@ class WindsurfRegister {
|
|||||||
this.human = new HumanBehavior();
|
this.human = new HumanBehavior();
|
||||||
this.emailService = new EmailVerificationService();
|
this.emailService = new EmailVerificationService();
|
||||||
this.capsolver = new CapSolverAPI();
|
this.capsolver = new CapSolverAPI();
|
||||||
|
this.yescaptcha = new YesCaptchaAPI();
|
||||||
|
|
||||||
|
// 初始化 2Captcha
|
||||||
|
const twoCaptchaKey = process.env.TWOCAPTCHA_API_KEY;
|
||||||
|
if (twoCaptchaKey && twoCaptchaKey !== '你的2Captcha_API_KEY') {
|
||||||
|
try {
|
||||||
|
this.twoCaptchaSolver = new Solver(twoCaptchaKey);
|
||||||
|
logger.info(this.siteName, ` → 2Captcha 已初始化 (Key: ${twoCaptchaKey.substring(0, 10)}...)`);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(this.siteName, ` → 2Captcha 初始化失败: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 YesCaptcha 配置
|
||||||
|
if (this.yescaptcha.apiKey) {
|
||||||
|
logger.info(this.siteName, ` → YesCaptcha 已初始化 (Key: ${this.yescaptcha.apiKey.substring(0, 10)}...)`);
|
||||||
|
}
|
||||||
|
|
||||||
// 浏览器管理器(支持多profile并发)
|
// 浏览器管理器(支持多profile并发)
|
||||||
this.browserManager = new BrowserManager({
|
this.browserManager = new BrowserManager({
|
||||||
@ -1039,33 +1058,26 @@ class WindsurfRegister {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试使用 CapSolver API 自动识别
|
// 优先尝试使用 YesCaptcha API
|
||||||
if (this.capsolver.apiKey) {
|
if (this.yescaptcha.apiKey) {
|
||||||
try {
|
try {
|
||||||
logger.info(this.siteName, ' → 使用 CapSolver API 自动识别...');
|
logger.info(this.siteName, ' → 使用 YesCaptcha API 自动识别...');
|
||||||
|
|
||||||
logger.info(this.siteName, ` → SiteKey: ${captchaInfo.siteKey.substring(0, 20)}...`);
|
logger.info(this.siteName, ` → SiteKey: ${captchaInfo.siteKey}`);
|
||||||
if (captchaInfo.callback) {
|
|
||||||
logger.info(this.siteName, ` → Callback: ${captchaInfo.callback}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 调用 CapSolver API 获取 token
|
|
||||||
// 简化 URL,移除 hash 和查询参数(CapSolver 不需要完整 URL)
|
|
||||||
const currentUrl = this.page.url();
|
const currentUrl = this.page.url();
|
||||||
const simplifiedUrl = new URL(currentUrl);
|
logger.info(this.siteName, ` → 页面 URL: ${currentUrl.substring(0, 80)}...`);
|
||||||
const cleanUrl = `${simplifiedUrl.protocol}//${simplifiedUrl.host}${simplifiedUrl.pathname}`;
|
|
||||||
|
|
||||||
logger.info(this.siteName, ` → 原始 URL: ${currentUrl.substring(0, 80)}...`);
|
// 调用 YesCaptcha API
|
||||||
logger.info(this.siteName, ` → 简化 URL: ${cleanUrl}`);
|
const token = await this.yescaptcha.solveHCaptcha(captchaInfo.siteKey, currentUrl, {
|
||||||
|
isInvisible: true // Stripe 使用 invisible hCaptcha
|
||||||
|
});
|
||||||
|
|
||||||
const token = await this.capsolver.solveHCaptcha(captchaInfo.siteKey, cleanUrl);
|
logger.info(this.siteName, ` → ✓ 获取到 token: ${token.substring(0, 30)}...`);
|
||||||
|
|
||||||
logger.info(this.siteName, ` → 获取到 token: ${token.substring(0, 30)}...`);
|
// 3. 注入 token 并触发回调(按正确顺序)
|
||||||
|
|
||||||
// 3. 注入 token 并触发回调
|
|
||||||
const injected = await this.page.evaluate((token, callbackName) => {
|
const injected = await this.page.evaluate((token, callbackName) => {
|
||||||
try {
|
try {
|
||||||
// 方法1: 设置到隐藏的 textarea
|
// 步骤1: 设置到隐藏的 textarea(必须)
|
||||||
const textarea = document.querySelector('[name="h-captcha-response"]');
|
const textarea = document.querySelector('[name="h-captcha-response"]');
|
||||||
const textareaG = document.querySelector('[name="g-recaptcha-response"]');
|
const textareaG = document.querySelector('[name="g-recaptcha-response"]');
|
||||||
if (textarea) {
|
if (textarea) {
|
||||||
@ -1077,24 +1089,55 @@ class WindsurfRegister {
|
|||||||
textareaG.innerHTML = token;
|
textareaG.innerHTML = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 方法2: 使用 hCaptcha API
|
// 步骤2: 执行回调函数(关键!)
|
||||||
if (window.hcaptcha && window.hcaptcha.setResponse) {
|
let callbackExecuted = false;
|
||||||
window.hcaptcha.setResponse(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方法3: 触发自定义回调(如果有)
|
// 方法A: 触发自定义回调(优先级最高)
|
||||||
if (callbackName && typeof window[callbackName] === 'function') {
|
if (callbackName && typeof window[callbackName] === 'function') {
|
||||||
window[callbackName](token);
|
window[callbackName](token);
|
||||||
return { success: true, method: 'callback', callback: callbackName };
|
callbackExecuted = true;
|
||||||
|
return { success: true, method: 'custom-callback', callback: callbackName };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 方法4: 触发 hCaptcha 回调事件
|
// 方法B: 使用 hcaptcha API 的 setResponse + callback
|
||||||
if (window.hcaptcha && window.hcaptcha.callback) {
|
if (window.hcaptcha) {
|
||||||
|
if (window.hcaptcha.setResponse) {
|
||||||
|
window.hcaptcha.setResponse(token);
|
||||||
|
callbackExecuted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发 hcaptcha 的回调
|
||||||
|
if (window.hcaptcha.callback && typeof window.hcaptcha.callback === 'function') {
|
||||||
window.hcaptcha.callback(token);
|
window.hcaptcha.callback(token);
|
||||||
return { success: true, method: 'hcaptcha.callback' };
|
return { success: true, method: 'hcaptcha.callback' };
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { success: true, method: 'textarea' };
|
// 方法C: 在所有 iframe 中查找回调
|
||||||
|
const frames = document.querySelectorAll('iframe');
|
||||||
|
for (const frame of frames) {
|
||||||
|
try {
|
||||||
|
if (frame.contentWindow && frame.contentWindow.hcaptcha) {
|
||||||
|
if (frame.contentWindow.hcaptcha.setResponse) {
|
||||||
|
frame.contentWindow.hcaptcha.setResponse(token);
|
||||||
|
}
|
||||||
|
if (frame.contentWindow.hcaptcha.callback) {
|
||||||
|
frame.contentWindow.hcaptcha.callback(token);
|
||||||
|
return { success: true, method: 'iframe-hcaptcha.callback' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 跨域iframe无法访问,跳过
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发 change 事件
|
||||||
|
if (textarea) {
|
||||||
|
const event = new Event('change', { bubbles: true });
|
||||||
|
textarea.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true, method: 'textarea-only', callbackExecuted };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { success: false, error: e.message };
|
return { success: false, error: e.message };
|
||||||
}
|
}
|
||||||
@ -1104,16 +1147,89 @@ class WindsurfRegister {
|
|||||||
throw new Error(`Token 注入失败: ${injected.error}`);
|
throw new Error(`Token 注入失败: ${injected.error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.success(this.siteName, ` → ✓ hCaptcha 自动识别成功 (方式: ${injected.method})`);
|
logger.success(this.siteName, ` → ✓ Token 注入成功 (方式: ${injected.method})`);
|
||||||
|
if (injected.callback) {
|
||||||
|
logger.info(this.siteName, ` → ✓ 已执行回调函数: ${injected.callback}`);
|
||||||
|
} else if (injected.callbackExecuted) {
|
||||||
|
logger.info(this.siteName, ' → ✓ 已执行 hCaptcha 回调');
|
||||||
|
} else {
|
||||||
|
logger.warn(this.siteName, ' → ⚠️ 未找到回调函数,可能需要手动触发');
|
||||||
|
}
|
||||||
|
logger.info(this.siteName, ' → 等待自动验证...');
|
||||||
|
|
||||||
|
// 不要主动点击 checkbox!YesCaptcha 的 token 应该自动通过
|
||||||
|
// 如果主动点击反而会触发 hCaptcha 的二次验证
|
||||||
|
await this.human.randomDelay(2000, 3000);
|
||||||
|
|
||||||
|
// 等待验证完成(如果回调成功,应该很快;如果降级到图片,需要手动)
|
||||||
|
logger.info(this.siteName, ' → 等待验证完成...');
|
||||||
|
const startTime = Date.now();
|
||||||
|
let dialogClosed = false;
|
||||||
|
let hasImageChallenge = false;
|
||||||
|
const maxWaitTime = 60000; // 最多60秒(包含图片挑战时间)
|
||||||
|
|
||||||
|
while (Date.now() - startTime < maxWaitTime) {
|
||||||
|
const status = await this.page.evaluate(() => {
|
||||||
|
const dialog = document.querySelector('[role="dialog"]');
|
||||||
|
if (!dialog) return { dialogGone: true, verified: true, hasImageChallenge: false };
|
||||||
|
|
||||||
|
const style = window.getComputedStyle(dialog);
|
||||||
|
const isHidden = style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0';
|
||||||
|
|
||||||
|
// 检查 token 是否已填充
|
||||||
|
const response = document.querySelector('[name="h-captcha-response"]') ||
|
||||||
|
document.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
const hasResponse = response && response.value && response.value.length > 20;
|
||||||
|
|
||||||
|
// 检查是否有图片挑战
|
||||||
|
const dialogText = dialog.innerText || '';
|
||||||
|
const hasImageTask = dialogText.includes('选择') ||
|
||||||
|
dialogText.includes('Select') ||
|
||||||
|
dialog.querySelector('img[src*="hcaptcha"]') ||
|
||||||
|
dialog.querySelector('[class*="task"]');
|
||||||
|
|
||||||
|
return {
|
||||||
|
dialogGone: !dialog || isHidden,
|
||||||
|
verified: hasResponse,
|
||||||
|
hasImageChallenge: hasImageTask,
|
||||||
|
dialogText: dialogText.substring(0, 80)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 第一次检测到图片挑战
|
||||||
|
if (status.hasImageChallenge && !hasImageChallenge) {
|
||||||
|
hasImageChallenge = true;
|
||||||
|
logger.warn(this.siteName, ' → ⚠️ Token 被降级,出现图片挑战!');
|
||||||
|
logger.info(this.siteName, ` → 任务: ${status.dialogText}`);
|
||||||
|
logger.warn(this.siteName, ' → 请手动完成图片验证...');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证完成
|
||||||
|
if (status.dialogGone || (status.verified && !status.hasImageChallenge)) {
|
||||||
|
dialogClosed = true;
|
||||||
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
||||||
|
logger.success(this.siteName, ` → ✓ 验证完成(耗时${elapsed}秒)`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态调整检查间隔
|
||||||
|
const interval = hasImageChallenge ? 2000 : 1000;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, interval));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dialogClosed) {
|
||||||
|
logger.warn(this.siteName, ' → ⚠️ 验证超时,继续尝试支付...');
|
||||||
|
}
|
||||||
|
|
||||||
await this.human.randomDelay(1000, 2000);
|
await this.human.randomDelay(1000, 2000);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(this.siteName, ` → ✗ CapSolver 自动识别失败: ${error.message}`);
|
logger.error(this.siteName, ` → ✗ YesCaptcha 自动识别失败: ${error.message}`);
|
||||||
logger.warn(this.siteName, ' → 将回退到手动模式');
|
logger.warn(this.siteName, ' → 将回退到手动模式');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn(this.siteName, ' → 未配置 CapSolver API Key');
|
logger.warn(this.siteName, ' → 未配置 YesCaptcha API Key');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 手动等待模式
|
// 手动等待模式
|
||||||
@ -1272,34 +1388,10 @@ class WindsurfRegister {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (captchaDetected) {
|
if (captchaDetected) {
|
||||||
logger.warn(this.siteName, ' → ⚠️ 检测到验证码,请手动完成(等待60秒)...');
|
logger.info(this.siteName, ' → 检测到验证码,使用 YesCaptcha API 处理...');
|
||||||
|
// 使用 YesCaptcha API 处理
|
||||||
// 等待用户手动完成验证码
|
await this.handleHCaptcha();
|
||||||
const waitStart = Date.now();
|
await this.human.randomDelay(1000, 2000);
|
||||||
const maxWait = 60000; // 等待60秒
|
|
||||||
|
|
||||||
while (Date.now() - waitStart < maxWait) {
|
|
||||||
// 检查验证码是否已完成
|
|
||||||
const captchaCompleted = await this.page.evaluate(() => {
|
|
||||||
// 检查验证码对话框是否消失
|
|
||||||
const modal = document.querySelector('[role="dialog"]');
|
|
||||||
const modalVisible = modal && window.getComputedStyle(modal).display !== 'none';
|
|
||||||
return !modalVisible;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (captchaCompleted) {
|
|
||||||
const elapsed = ((Date.now() - waitStart) / 1000).toFixed(1);
|
|
||||||
logger.success(this.siteName, ` → ✓ 验证码已完成(耗时${elapsed}秒)`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 每秒检查一次
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Date.now() - waitStart >= maxWait) {
|
|
||||||
logger.warn(this.siteName, ' → ⚠️ 验证码等待超时,继续尝试...');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logger.info(this.siteName, ` → ✓ 无验证码(检查${captchaCheckCount}次,耗时${((Date.now() - checkStartTime) / 1000).toFixed(1)}秒)`);
|
logger.info(this.siteName, ` → ✓ 无验证码(检查${captchaCheckCount}次,耗时${((Date.now() - checkStartTime) / 1000).toFixed(1)}秒)`);
|
||||||
}
|
}
|
||||||
|
|||||||
132
src/tools/account-register/utils/yescaptcha-api.js
Normal file
132
src/tools/account-register/utils/yescaptcha-api.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const logger = require('../../../shared/logger');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YesCaptcha API 封装
|
||||||
|
* 支持 hCaptcha、reCaptcha、Turnstile 等验证码识别
|
||||||
|
*/
|
||||||
|
class YesCaptchaAPI {
|
||||||
|
constructor() {
|
||||||
|
this.apiKey = process.env.YESCAPTCHA_API_KEY;
|
||||||
|
this.apiUrl = 'https://api.yescaptcha.com';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别 hCaptcha
|
||||||
|
* @param {string} siteKey - 网站的 sitekey
|
||||||
|
* @param {string} pageUrl - 网页 URL
|
||||||
|
* @param {object} options - 可选参数 {isInvisible, rqdata, userAgent}
|
||||||
|
* @returns {Promise<string>} - hCaptcha token
|
||||||
|
*/
|
||||||
|
async solveHCaptcha(siteKey, pageUrl, options = {}) {
|
||||||
|
if (!this.apiKey) {
|
||||||
|
throw new Error('YesCaptcha API Key 未配置');
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('YesCaptcha', '开始识别 hCaptcha...');
|
||||||
|
logger.info('YesCaptcha', `SiteKey: ${siteKey.substring(0, 20)}...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 创建任务
|
||||||
|
const requestBody = {
|
||||||
|
clientKey: this.apiKey,
|
||||||
|
task: {
|
||||||
|
type: 'HCaptchaTaskProxyless',
|
||||||
|
websiteURL: pageUrl,
|
||||||
|
websiteKey: siteKey
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加可选参数
|
||||||
|
if (options.isInvisible !== undefined) {
|
||||||
|
requestBody.task.isInvisible = options.isInvisible;
|
||||||
|
}
|
||||||
|
if (options.rqdata) {
|
||||||
|
requestBody.task.rqdata = options.rqdata;
|
||||||
|
}
|
||||||
|
if (options.userAgent) {
|
||||||
|
requestBody.task.userAgent = options.userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('YesCaptcha', `请求 URL: ${pageUrl}`);
|
||||||
|
logger.info('YesCaptcha', `API Key: ${this.apiKey.substring(0, 10)}...`);
|
||||||
|
|
||||||
|
const createTaskResponse = await axios.post(`${this.apiUrl}/createTask`, requestBody);
|
||||||
|
|
||||||
|
if (createTaskResponse.data.errorId !== 0) {
|
||||||
|
logger.error('YesCaptcha', `API 返回错误: ${JSON.stringify(createTaskResponse.data)}`);
|
||||||
|
throw new Error(`创建任务失败: ${createTaskResponse.data.errorDescription}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taskId = createTaskResponse.data.taskId;
|
||||||
|
logger.info('YesCaptcha', `任务已创建,TaskID: ${taskId}`);
|
||||||
|
|
||||||
|
// 2. 轮询获取结果(最多等待120秒)
|
||||||
|
const maxAttempts = 40; // 120秒 / 3秒
|
||||||
|
let attempts = 0;
|
||||||
|
|
||||||
|
while (attempts < maxAttempts) {
|
||||||
|
attempts++;
|
||||||
|
|
||||||
|
// 等待3秒再查询
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
|
||||||
|
logger.info('YesCaptcha', `查询结果... (${attempts}/${maxAttempts})`);
|
||||||
|
|
||||||
|
const getResultResponse = await axios.post(`${this.apiUrl}/getTaskResult`, {
|
||||||
|
clientKey: this.apiKey,
|
||||||
|
taskId: taskId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (getResultResponse.data.errorId !== 0) {
|
||||||
|
throw new Error(`查询结果失败: ${getResultResponse.data.errorDescription}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = getResultResponse.data.status;
|
||||||
|
|
||||||
|
if (status === 'ready') {
|
||||||
|
const token = getResultResponse.data.solution.gRecaptchaResponse;
|
||||||
|
logger.success('YesCaptcha', `✓ 识别成功!耗时: ${attempts * 3}秒`);
|
||||||
|
|
||||||
|
// 返回 userAgent 如果有的话
|
||||||
|
if (getResultResponse.data.solution.userAgent) {
|
||||||
|
logger.info('YesCaptcha', `返回的 UserAgent: ${getResultResponse.data.solution.userAgent.substring(0, 50)}...`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
} else if (status === 'processing') {
|
||||||
|
// 继续等待
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
throw new Error(`未知状态: ${status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('识别超时(120秒)');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// 详细的错误日志
|
||||||
|
if (error.response) {
|
||||||
|
// API 返回了错误响应
|
||||||
|
logger.error('YesCaptcha', `HTTP ${error.response.status}: ${error.response.statusText}`);
|
||||||
|
logger.error('YesCaptcha', `响应数据: ${JSON.stringify(error.response.data)}`);
|
||||||
|
|
||||||
|
if (error.response.status === 400) {
|
||||||
|
logger.error('YesCaptcha', '可能原因:');
|
||||||
|
logger.error('YesCaptcha', ' 1. API Key 无效或已过期');
|
||||||
|
logger.error('YesCaptcha', ' 2. 余额不足');
|
||||||
|
logger.error('YesCaptcha', ' 3. siteKey 或 URL 格式错误');
|
||||||
|
}
|
||||||
|
} else if (error.request) {
|
||||||
|
// 请求已发送但没有收到响应
|
||||||
|
logger.error('YesCaptcha', '无法连接到 YesCaptcha API');
|
||||||
|
} else {
|
||||||
|
// 其他错误
|
||||||
|
logger.error('YesCaptcha', `识别失败: ${error.message}`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = YesCaptchaAPI;
|
||||||
Loading…
Reference in New Issue
Block a user