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

Express/request如何流式代理超大文件 无需服务器端全量下载

Node.js大视频分块流式代理实现方案

原代码问题根因

你当前的代码出现「服务器先缓存全量文件再发送给客户端」的问题,核心原因有三点:

  • 没有处理HTTP Range 请求头:视频客户端(浏览器、播放器)默认会携带Range头请求文件分块,你的代码没有透传该头到源站,源站会返回完整15GB文件的200响应,客户端收到不带Accept-Ranges标识的响应后,会默认等待全量文件接收完成才开始处理
  • 大概率被响应缓冲中间件拦截:如果你的路由前挂载了compression、body-parser等会缓冲响应体的中间件,会自动把流式响应暂存在内存/磁盘,等全量接收完成后才发送给客户端,直接破坏流式传输逻辑
  • 已废弃的request库本身存在流控缺陷,大文件传输时容易出现内存堆积问题。

最优实现方案

核心原则是透传分块相关头、不做任何响应缓冲、直接流式转发,Node.js 18+ 可以直接用内置的fetch实现,无需额外安装第三方请求库:

const { Readable } = require('node:stream');
const express = require('express');
const cors = require('cors');
const app = express();

// 注意:该路由必须注册在compression、body-parser等会缓冲响应的中间件之前
app.all('/shareRedirects/*', cors({origin: '*'}), async (req, res) => {
  // 替换为你实际的源站基础地址
  const ORIGIN_BASE = 'https://你的源站存储地址/';
  const targetUrl = new URL(req.params[0], ORIGIN_BASE).toString();

  try {
    // 透传分块请求头到源站
    const upstreamResp = await fetch(targetUrl, {
      method: req.method,
      headers: {
        ...(req.headers.range ? { Range: req.headers.range } : {}),
        // 源站需要鉴权的话在这里加对应鉴权头即可
      },
      highWaterMark: 1024 * 1024, // 单块大小设为1MB,平衡内存占用和传输性能
    });

    // 原样返回源站的状态码(分块请求会返回206 Partial Content)
    res.status(upstreamResp.status);

    // 透传分块传输核心响应头
    const PASS_HEADERS = ['content-type', 'content-length', 'content-range', 'accept-ranges', 'cache-control', 'last-modified', 'etag'];
    PASS_HEADERS.forEach(headerKey => {
      const headerVal = upstreamResp.headers.get(headerKey);
      if (headerVal) res.setHeader(headerKey, headerVal);
    });

    // 直接将上游流转发到客户端响应,不做全量缓存
    const upstreamStream = Readable.fromWeb(upstreamResp.body);
    upstreamStream.pipe(res);

    // 处理连接断开的资源释放
    res.on('close', () => upstreamStream.destroy());
    upstreamStream.on('error', (err) => {
      if (!res.headersSent) res.sendStatus(500);
      upstreamStream.destroy();
    });
  } catch (err) {
    if (!res.headersSent) res.sendStatus(500);
  }
});

app.listen(3000);

关键注意事项

  • 禁止给该路由挂载响应压缩中间件:压缩逻辑需要读取完整响应体才能计算压缩结果,会强制触发全量缓冲,15GB文件会直接占满服务器内存
  • 单块大小highWaterMark不要设置超过2MB,否则高并发场景下内存占用会快速升高
  • 该方案天然支持视频进度条拖动、断点续传,不需要额外写逻辑处理分块计算,所有分块逻辑由源站处理,代理层只做透传
  • 如果使用Node.js 18以下版本,把内置fetch替换为undici库的fetch实现即可,性能和流稳定性远高于已废弃的request库

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:06:21