You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将AWS S3中的大文件(视频、PDF等)流式传输到Node.js Express响应?

实现S3对象的分段下载(支持Range请求)

我看你已经在尝试用s3fs实现S3对象的分段下载了,我帮你把代码整理完善成可运行的版本,顺便解释下关键要点:

核心逻辑说明

  • 先初始化S3FS实例,配置你的AWS密钥和目标桶名
  • 解析请求头里的Range字段,没有的话默认从起始位置下载整个文件
  • 计算要返回的字节范围、分片大小,设置对应的响应头(这是分段下载的关键)
  • 通过流式读取S3对象并返回给客户端,避免内存过载

完整代码实现

const S3FS = require('s3fs');

// 初始化S3FS实例,替换成你的配置
const bucketName = 'your-bucket-name';
const accessKeyId = 'your-access-key-id';
const secretAccessKey = 'your-secret-access-key';
const s3fsImpl = new S3FS(bucketName, { accessKeyId, secretAccessKey });

// 处理请求的函数示例
async function handleS3RangeRequest(req, res) {
  try {
    // 替换成你要获取的S3对象键名
    const objectKey = 'your-object-key';
    // 获取S3对象的元数据,拿到文件总大小
    const details = await s3fsImpl.stat(objectKey);
    const contentType = details.ContentType || 'application/octet-stream';
    const total = details.ContentLength;

    // 解析Range请求头,没有的话默认从0开始下载全部
    const range = req.headers.range || 'bytes=0-';
    const positions = range.replace(/bytes=/, "").split("-");
    const start = parseInt(positions[0], 10);
    // 如果没有指定结束位置,默认到文件末尾
    const end = positions[1] ? parseInt(positions[1], 10) : total - 1;
    const chunksize = (end - start) + 1;

    // 设置分段下载的响应头
    res.setHeader("Content-Type", contentType);
    res.setHeader("Content-Length", chunksize);
    res.setHeader("Content-Range", `bytes ${start}-${end}/${total}`);
    res.setHeader("Accept-Ranges", "bytes");
    // 返回206 Partial Content状态码
    res.statusCode = 206;

    // 创建S3对象的只读流,指定字节范围
    const stream = s3fsImpl.createReadStream(objectKey, { start, end });
    // 把流pipe到响应对象
    stream.pipe(res);

    // 处理流的错误
    stream.on('error', (err) => {
      console.error('读取S3对象出错:', err);
      res.status(500).send('Internal Server Error');
    });
  } catch (err) {
    console.error('处理请求出错:', err);
    res.status(500).send('Internal Server Error');
  }
}

关键注意点

  • 状态码:分段下载必须返回206 Partial Content,而不是200,这样客户端才能正确识别分段响应
  • 响应头Content-Range是核心,格式必须是bytes start-end/total,客户端靠这个来拼接分段数据
  • 流式处理:用createReadStream而不是直接读取整个文件,尤其是大文件场景,能有效减少内存占用
  • 错误处理:一定要处理流的错误和异步操作的错误,避免请求挂起或者崩溃

内容的提问来源于stack exchange,提问作者sky great

火山引擎 最新活动