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

Node.js Express服务端通过外部链接代理下载返回0字节文件如何解决

问题根因

  • 你设置了responseType: 'stream'时,axios返回的response.data是可读流对象,不是已经下载完成的完整二进制数据,此时直接读取response.data.length天然为0,调用res.end(Buffer.from(response.data, 'binary'))本质是写入了空内容,自然得到0字节文件。
  • 外部资源使用Transfer-Encoding: chunked分块传输,本身不会返回Content-Length响应头,强行设置该字段会导致传输长度不匹配提前中断。

解决方案

使用流管道(pipe)直接把axios拿到的可读流转发给Express的响应对象,不需要等文件全部下载到Node.js服务端再返回,边下载边转发,同时适配分块传输的场景。

正确实现代码

// Express.js route
const axios = require('axios');
const { pipeline } = require('stream');
const { promisify } = require('util');
const pipelineAsync = promisify(pipeline); // 用promise版pipeline更方便处理错误

// 你的路由处理函数
app.get('/proxy-download', async (req, res, next) => {
  try {
    const externalLink = '你的外部文件地址';
    const axiosRes = await axios({
      method: 'GET',
      url: externalLink,
      responseType: 'stream',
    });

    // 设置响应头,不要硬写Content-Length
    res.writeHead(200, {
      'Content-Type': EXCEL_MIME_TYPE,
      'Content-Disposition': axiosRes.headers['content-disposition'],
    });

    // 用pipeline管道传输,自动处理流的结束、错误销毁
    await pipelineAsync(axiosRes.data, res);
  } catch (err) {
    // 处理错误,比如外部链接请求失败、传输中断等
    if (!res.headersSent) {
      res.status(500).send('文件下载失败');
    }
    next(err);
  }
});

实现说明

  • pipeline是Node.js官方推荐的流传输方法,相比原生pipe会自动处理流出错时的资源销毁,避免内存泄漏。
  • 不需要手动设置Content-Length,分块传输场景下Node.js会自动添加Transfer-Encoding: chunked头,客户端会自动接收完整内容。
  • 流是边接收边转发,即使是GB级的大文件也不会占用Node.js服务端过多内存。
  • 可选优化:如果下载的文件名出现乱码,可以使用content-disposition包解析外部返回的content-disposition头,再重新编码后设置给客户端。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 23:18:00