From bc0b1ed76afc1dc3c478e9a0d3f411512e572ed3 Mon Sep 17 00:00:00 2001 From: MianJu <2462692286@qq.com> Date: Fri, 7 Aug 2026 19:50:00 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E9=87=8D=E5=AE=9A=E5=90=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/fileCache.ts | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/server/fileCache.ts b/src/server/fileCache.ts index 19646de..b51c0c7 100644 --- a/src/server/fileCache.ts +++ b/src/server/fileCache.ts @@ -1965,9 +1965,10 @@ export const downloadAndCache = async (songInfo: any, url: string, quality?: str console.log(`[FileCache] Starting download for: ${baseName}`) return new Promise((resolve, reject) => { - const protocol = url.startsWith('https') ? https : http let req: http.ClientRequest let settled = false + let redirectCount = 0 + const MAX_REDIRECTS = 10 const fail = (err: Error) => { if (settled) return @@ -1992,12 +1993,41 @@ export const downloadAndCache = async (songInfo: any, url: string, quality?: str if (signal) signal.addEventListener('abort', abortHandler) - req = protocol.get(url, (res) => { - if (res.statusCode !== 200) { - fs.unlink(tempPath, () => { }) - fail(new Error(`Status: ${res.statusCode}`)) + // 递归下载,自动跟随 3xx 重定向(浏览器会自动跟随,但 http.get 不会) + const downloadFrom = (currentUrl: string) => { + if (signal?.aborted) { + fail(new Error('Aborted')) return } + const protocol = currentUrl.startsWith('https') ? https : http + req = protocol.get(currentUrl, (res) => { + const status = res.statusCode || 0 + // 处理重定向:301/302/303/307/308 + if ([301, 302, 303, 307, 308].includes(status)) { + const location = res.headers['location'] + res.resume() // 消费响应体,避免连接挂起 + if (!location) { + fs.unlink(tempPath, () => { }) + fail(new Error(`Status: ${status} (missing Location header)`)) + return + } + if (redirectCount >= MAX_REDIRECTS) { + fs.unlink(tempPath, () => { }) + fail(new Error(`Too many redirects (${MAX_REDIRECTS})`)) + return + } + redirectCount++ + const nextUrl = new URL(location, currentUrl).toString() + console.log(`[FileCache] Redirect ${status} -> ${nextUrl} (${redirectCount}/${MAX_REDIRECTS})`) + downloadFrom(nextUrl) + return + } + if (status !== 200) { + fs.unlink(tempPath, () => { }) + fail(new Error(`Status: ${status}`)) + return + } + cacheProgress.set(songKey, { progress: 0, status: 'downloading', total: 0, received: 0, speed: 0, updatedAt: Date.now() }) const total = parseInt(res.headers['content-length'] || '0', 10) @@ -2164,6 +2194,9 @@ export const downloadAndCache = async (songInfo: any, url: string, quality?: str req.setTimeout(30000, () => { req.destroy(new Error('Download request timeout')) }) + } + + downloadFrom(url) }) }