diff --git a/src/app/api/music/audio-proxy/route.ts b/src/app/api/music/audio-proxy/route.ts index 37ed724..84254c0 100644 --- a/src/app/api/music/audio-proxy/route.ts +++ b/src/app/api/music/audio-proxy/route.ts @@ -70,6 +70,22 @@ export async function GET(request: NextRequest) { // 检查是否有 Range 请求头 const range = request.headers.get('range'); + const ifNoneMatch = request.headers.get('if-none-match'); + const ifModifiedSince = request.headers.get('if-modified-since'); + + // 生成基于文件路径的 ETag + const generatedETag = `"${Buffer.from(audioPath).toString('base64')}"`; + + // 如果客户端发送了 If-None-Match,检查是否匹配 + if (ifNoneMatch && ifNoneMatch === generatedETag) { + return new NextResponse(null, { + status: 304, + headers: { + 'Cache-Control': 'public, max-age=31536000, immutable', + 'ETag': generatedETag, + }, + }); + } // 构建上游请求头 const upstreamHeaders: Record = { @@ -81,11 +97,30 @@ export async function GET(request: NextRequest) { upstreamHeaders['Range'] = range; } + // 转发条件请求头到上游 + if (ifNoneMatch) { + upstreamHeaders['If-None-Match'] = ifNoneMatch; + } + if (ifModifiedSince) { + upstreamHeaders['If-Modified-Since'] = ifModifiedSince; + } + // 从OpenList获取音频流 const response = await fetch(fileResponse.data.raw_url, { headers: upstreamHeaders, }); + // 如果上游返回 304 Not Modified,直接返回 304 + if (response.status === 304) { + return new NextResponse(null, { + status: 304, + headers: { + 'Cache-Control': 'public, max-age=31536000, immutable', + 'ETag': generatedETag, + }, + }); + } + if (!response.ok && response.status !== 206) { return NextResponse.json( { error: '获取音频失败' }, @@ -98,6 +133,8 @@ export async function GET(request: NextRequest) { const contentLength = response.headers.get('content-length'); const contentRange = response.headers.get('content-range'); const acceptRanges = response.headers.get('accept-ranges'); + const etag = response.headers.get('etag'); + const lastModified = response.headers.get('last-modified'); // 创建响应头 - 设置永久缓存 const headers: Record = { @@ -117,6 +154,19 @@ export async function GET(request: NextRequest) { headers['Content-Range'] = contentRange; } + // 转发 ETag 和 Last-Modified 以支持浏览器缓存验证 + if (etag) { + headers['ETag'] = etag; + } + if (lastModified) { + headers['Last-Modified'] = lastModified; + } + + // 如果上游没有提供 ETag,使用生成的 ETag + if (!etag) { + headers['ETag'] = generatedETag; + } + // 返回音频流,保持原始状态码(200 或 206) return new NextResponse(response.body, { status: response.status,