基于Next.js与CDN的大文件流式下载打包方案问询
流式打包并传输大文件的Next.js解决方案
针对你遇到的问题,核心是利用流式压缩+HTTP分块传输,让服务器一边打包一边向浏览器发送数据,无需等待全部文件压缩完成再触发下载。下面是基于Next.js的可行实现方案:
1. 依赖准备
先安装流式压缩库和S3客户端:
npm install zip-stream @aws-sdk/client-s3 # 或用yarn yarn add zip-stream @aws-sdk/client-s3
2. Next.js App Router 实现
如果使用App Router,直接通过StreamingResponse返回流:
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import ZipStream from "zip-stream"; export async function GET() { // 初始化S3客户端 const s3Client = new S3Client({ region: "你的S3存储区域", credentials: { accessKeyId: "你的AccessKey", secretAccessKey: "你的SecretKey", }, }); // 创建zip流式压缩实例 const zip = new ZipStream(); // 定义需要打包的S3文件列表 const filesToZip = [ { key: "file1.pdf", name: "文档1.pdf" }, { key: "large-video.mp4", name: "视频.mp4" }, // 可添加更多文件 ]; // 异步逐个添加文件到zip流 (async () => { for (const file of filesToZip) { try { // 从S3获取文件流 const s3Response = await s3Client.send( new GetObjectCommand({ Bucket: "你的Bucket名称", Key: file.key }) ); // 将S3流写入zip await new Promise((resolve, reject) => { zip.entry(s3Response.Body, { name: file.name }, (err) => { err ? reject(err) : resolve(); }); }); } catch (err) { console.error(`添加文件失败: ${file.key}`, err); zip.destroy(err); return; } } // 结束zip流 zip.finalize(); })(); // 设置响应头,触发浏览器立即下载 const headers = new Headers(); headers.set("Content-Type", "application/zip"); headers.set("Content-Disposition", 'attachment; filename="打包文件.zip"'); headers.set("Transfer-Encoding", "chunked"); return new StreamingResponse(zip, { headers }); }
3. Next.js Pages Router 兼容版本
如果使用Pages Router,直接操作响应对象写流:
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import ZipStream from "zip-stream"; export default async function handler(req, res) { if (req.method !== "GET") { res.status(405).end(); return; } const s3Client = new S3Client({ region: "你的S3存储区域", credentials: { accessKeyId: "你的AccessKey", secretAccessKey: "你的SecretKey", }, }); const zip = new ZipStream(); // 设置响应头 res.setHeader("Content-Type", "application/zip"); res.setHeader("Content-Disposition", 'attachment; filename="打包文件.zip"'); res.setHeader("Transfer-Encoding", "chunked"); // 将zip流管道到响应对象 zip.pipe(res); const filesToZip = [ { key: "file1.pdf", name: "文档1.pdf" }, { key: "large-video.mp4", name: "视频.mp4" }, ]; try { for (const file of filesToZip) { const s3Response = await s3Client.send( new GetObjectCommand({ Bucket: "你的Bucket名称", Key: file.key }) ); await new Promise((resolve, reject) => { zip.entry(s3Response.Body, { name: file.name }, (err) => { err ? reject(err) : resolve(); }); }); } zip.finalize(); } catch (err) { console.error("打包出错", err); zip.destroy(err); res.status(500).end(); } }
4. 关键注意事项
- 响应头配置:
Transfer-Encoding: chunked是核心,告诉浏览器采用分块传输;Content-Disposition指定文件名,让浏览器立即触发下载流程。 - 错误处理:若某个S3文件获取失败,调用
zip.destroy(err)终止流,避免客户端无限等待。 - 内存优化:流式处理不会将整个文件或压缩包加载到内存,适合大文件场景,防止服务器内存溢出。
- 版本兼容:App Router的
StreamingResponse需要Next.js 13.4及以上版本,旧版本建议使用Pages Router方案。
内容的提问来源于stack exchange,提问作者Valentincognito
相关产品推荐
相关产品推荐

