mirror of
https://github.com/foxhui/WebAI2API.git
synced 2026-06-16 21:03:59 +08:00
feat: 图片下载重试机制优化
- 新增 isRetryableError() 判断网络错误是否可重试 - 默认启用重试 (maxRetries=3) - 5xx 错误自动重试 - 网络超时、断开等错误智能重试 - 增加重试延迟(指数退避) - 返回 imageUrl 便于失败后重试 - 超时延长到 120s
This commit is contained in:
@@ -3,6 +3,17 @@
|
||||
* @description 图片下载与 Base64 转换
|
||||
*/
|
||||
|
||||
import { logger } from '../../utils/logger.js';
|
||||
|
||||
/**
|
||||
* 判断错误是否可重试
|
||||
* @param {string} message - 错误消息
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isRetryableError(message) {
|
||||
return /timeout|network|econnreset|econnrefused|etimedout|disconnected|tls|socket/i.test(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用页面上下文下载图片并转换为 Base64
|
||||
* 自动继承页面的 Cookie 和 Session,解决鉴权问题
|
||||
@@ -10,19 +21,26 @@
|
||||
* @param {import('playwright-core').Page} page - Playwright 页面对象
|
||||
* @param {object} [options] - 可选配置
|
||||
* @param {number} [options.timeout=60000] - 超时时间(毫秒)
|
||||
* @param {number} [options.retries=0] - 下载失败时的重试次数
|
||||
* @returns {Promise<{ image?: string, error?: string }>} 下载结果
|
||||
* @param {number} [options.maxRetries=3] - 最大重试次数
|
||||
* @param {number} [options.retryDelay=1000] - 重试延迟基数(毫秒)
|
||||
* @returns {Promise<{ image?: string, imageUrl?: string, error?: string }>} 下载结果(包含原始 URL)
|
||||
*/
|
||||
export async function useContextDownload(url, page, options = {}) {
|
||||
const { timeout = 60000, retries = 0 } = options;
|
||||
const { timeout = 120000, maxRetries = 3, retryDelay = 1000 } = options;
|
||||
|
||||
for (let attempt = 0; attempt <= retries; attempt++) {
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
const response = await page.request.get(url, { timeout });
|
||||
|
||||
if (!response.ok()) {
|
||||
if (attempt < retries) continue;
|
||||
return { error: `下载失败: HTTP ${response.status()}` };
|
||||
const status = response.status();
|
||||
// 5xx 错误可重试
|
||||
if (status >= 500 && attempt < maxRetries) {
|
||||
logger.warn('下载', `HTTP ${status},重试 ${attempt}/${maxRetries}...`);
|
||||
await new Promise(r => setTimeout(r, retryDelay * attempt));
|
||||
continue;
|
||||
}
|
||||
return { error: `下载失败: HTTP ${status}`, imageUrl: url };
|
||||
}
|
||||
|
||||
const buffer = await response.body();
|
||||
@@ -30,10 +48,16 @@ export async function useContextDownload(url, page, options = {}) {
|
||||
const contentType = response.headers()['content-type'] || 'image/png';
|
||||
const mimeType = contentType.split(';')[0].trim();
|
||||
|
||||
return { image: `data:${mimeType};base64,${base64}` };
|
||||
return { image: `data:${mimeType};base64,${base64}`, imageUrl: url };
|
||||
} catch (e) {
|
||||
if (attempt < retries) continue;
|
||||
return { error: `已获取结果,但图片下载时遇到错误: ${e.message}` };
|
||||
if (isRetryableError(e.message) && attempt < maxRetries) {
|
||||
logger.warn('下载', `${e.message},重试 ${attempt}/${maxRetries}...`);
|
||||
await new Promise(r => setTimeout(r, retryDelay * attempt));
|
||||
continue;
|
||||
}
|
||||
return { error: `已获取结果,但图片下载时遇到错误: ${e.message}`, imageUrl: url };
|
||||
}
|
||||
}
|
||||
|
||||
return { error: '下载失败: 已达最大重试次数', imageUrl: url };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user