Cloudflare代理的Next.js R2文件端点首次处理音频Range请求时永久Pending问题求助
Cloudflare代理的Next.js R2文件端点首次处理音频Range请求时永久Pending问题求助
大家好,我最近在开发一个支持用户上传和播放音频的平台,基于NextJS构建,用Cloudflare R2做文件存储。前端通过NextJS的/bucket/[filename]端点获取音频文件,这个端点会被Cloudflare代理并缓存。目前遇到一个非常棘手的问题,想请社区帮忙分析下:
问题现象
- 上传音频文件到R2后,第一次在前端尝试播放时,音频完全无法加载或播放
- 手动清除Cloudflare中对应
/bucket/[filename]端点的缓存后,音频能正常播放,且之后一直没有问题(说明音频文件本身没有损坏) - 抓包观察请求流程:
- 第一个请求:Cloudflare缓存MISS(符合首次请求的预期),返回响应头但几乎没有数据
- 第二个请求:紧接着发送,Cloudflare缓存HIT,但请求一直处于Pending状态,永远不会返回响应体
我的推测
我怀疑问题和Cloudflare缓存处理Range请求头的逻辑有关。因为<audio>标签会携带这个请求头,目的是分片加载音频而非一次性下载整个文件,这个头是音频正常播放的必要条件。
端点实现细节
我的/bucket/[filename]端点本质是转发R2的GET请求,用@aws-sdk/client-s3(S3 API)和R2交互,代码如下:
import { GetObjectCommand } from "@aws-sdk/client-s3"; import { S3 } from "../../../../lib/s3"; import { NextRequest } from "next/server"; export async function GET( req: NextRequest, { params }: { params: Promise<{ fileId: string }> } ) { const { fileId } = await params; const data = await S3.send( new GetObjectCommand({ Key: fileId, Bucket: process.env.R2_BUCKET!, Range: req.headers.get("Range") ?? undefined, }) ); const dataStream = data.Body?.transformToWebStream(); // 省略错误处理和Content-Type校验逻辑... return new Response(dataStream, { headers: { "Content-Type": contentType, ...(data.ContentLength ? { "Content-Length": `${data.ContentLength}` } : {}), ...(data.AcceptRanges ? { "Accept-Ranges": `${data.AcceptRanges}` } : {}), ...(data.ContentRange ? { "Content-Range": `${data.ContentRange}` } : {}), ...(data.ETag ? { ETag: `${data.ETag}` } : {}), "Cache-Control": "public, max-age=15552000, immutable", // 6个月缓存,和Cloudflare缓存规则匹配 }, status: data.$metadata.httpStatusCode ?? 200, }); }
额外细节
虽然音频文件只有50MB,但首次加载的Pending状态非常顽固,偶尔刷新3-4次后能成功加载,但也要等待30秒以上,完全不符合预期。我猜测是Cloudflare在缓存带Range头的响应时出现了异常,导致后续的缓存命中请求无法正常返回分片数据。
有没有同学遇到过类似的问题?或者能给我一些排查方向、配置调整建议?非常感谢!
内容来源于stack exchange
相关产品推荐
相关产品推荐

