You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:21:21