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

能否实现无存储式文件边下载边上传?求NodeJS样板代码

NodeJS 边下载边上传流式传输实现方案

源端与目标端的要求

源端

必须支持流式下载:

  • HTTP源需支持Transfer-Encoding: chunked编码(现代服务器如Nginx、Apache默认启用),或允许按范围请求文件;
  • 核心是服务器能分块返回数据,而非一次性发送完整文件。

目标端

需满足以下任一条件:

  1. 支持流式上传:允许接收Transfer-Encoding: chunked的请求,无需提前知道文件总大小(多数现代服务器支持);
  2. 支持分块上传:若目标有大文件限制(如单文件上限1GB),需按其API协议拆分数据块上传(需额外处理块索引、合并逻辑)。

原生模块实现样板代码

使用NodeJS内置http/https模块,直接将下载流管道到上传流,内存仅保留当前处理的数据块:

const http = require('http');
const https = require('https');

// 根据URL协议选择对应的客户端模块
const getProtocolClient = (url) => new URL(url).protocol === 'https:' ? https : http;

function streamTransfer(sourceUrl, targetUrl) {
  return new Promise((resolve, reject) => {
    const sourceClient = getProtocolClient(sourceUrl);
    const targetClient = getProtocolClient(targetUrl);

    // 发起源文件下载请求
    sourceClient.get(sourceUrl, (sourceRes) => {
      // 校验源端响应状态
      if (sourceRes.statusCode < 200 || sourceRes.statusCode >= 300) {
        return reject(new Error(`源端请求失败:状态码 ${sourceRes.statusCode}`));
      }

      // 配置目标上传请求参数
      const targetUrlObj = new URL(targetUrl);
      const targetOptions = {
        hostname: targetUrlObj.hostname,
        port: targetUrlObj.port,
        path: targetUrlObj.pathname + targetUrlObj.search,
        method: 'PUT', // 按需改为POST,匹配目标端接口要求
        headers: {
          // 若目标端需要Content-Length,从源端响应头获取
          ...(sourceRes.headers['content-length'] ? { 'Content-Length': sourceRes.headers['content-length'] } : {}),
          'Content-Type': sourceRes.headers['content-type'] || 'application/octet-stream',
          // 按需添加认证头,如Authorization: Bearer xxx
        }
      };

      // 发起目标上传请求
      const targetReq = targetClient.request(targetOptions, (targetRes) => {
        // 校验目标端响应状态
        if (targetRes.statusCode < 200 || targetRes.statusCode >= 300) {
          return reject(new Error(`目标端上传失败:状态码 ${targetRes.statusCode}`));
        }
        resolve({
          sourceStatusCode: sourceRes.statusCode,
          targetStatusCode: targetRes.statusCode
        });
      });

      // 处理流错误
      sourceRes.on('error', (err) => reject(new Error(`源端流错误:${err.message}`)));
      targetReq.on('error', (err) => reject(new Error(`目标端请求错误:${err.message}`)));

      // 管道传输:源端响应流 → 目标端请求流
      sourceRes.pipe(targetReq);
    }).on('error', (err) => reject(new Error(`源端请求初始化失败:${err.message}`)));
  });
}

// 使用示例
streamTransfer('http://example.com/large-file.zip', 'http://your-target-server.com/upload')
  .then(result => console.log('传输完成:', result))
  .catch(err => console.error('传输失败:', err));

第三方库简化实现(Axios)

借助Axios的流式支持,代码更简洁:

const axios = require('axios');

async function streamTransferWithAxios(sourceUrl, targetUrl) {
  try {
    // 获取源文件流
    const sourceResponse = await axios.get(sourceUrl, { responseType: 'stream' });
    if (sourceResponse.status < 200 || sourceResponse.status >= 300) {
      throw new Error(`源端请求失败:状态码 ${sourceResponse.status}`);
    }

    // 上传流到目标端
    const targetResponse = await axios.put(targetUrl, sourceResponse.data, {
      headers: {
        'Content-Type': sourceResponse.headers['content-type'] || 'application/octet-stream',
        ...(sourceResponse.headers['content-length'] ? { 'Content-Length': sourceResponse.headers['content-length'] } : {}),
        // 按需添加认证头
      }
    });

    return {
      sourceStatusCode: sourceResponse.status,
      targetStatusCode: targetResponse.status
    };
  } catch (error) {
    throw new Error(`传输失败:${error.message}`);
  }
}

// 使用示例
streamTransferWithAxios('https://example.com/large-file.iso', 'https://your-target-server.com/upload')
  .then(res => console.log('传输完成:', res))
  .catch(err => console.error('传输失败:', err));

分块上传场景说明

如果目标端强制要求分块上传(如每个块10MB),需拆分数据流并按目标API协议提交:

  1. 监听源流的data事件,积累数据到指定大小后提交;
  2. 记录每个块的索引、总块数,按目标要求的参数发送;
  3. 所有块上传完成后,调用目标端的合并接口完成文件组装。

这种场景需根据目标端的具体API文档实现,没有通用样板,但核心仍是基于流式处理控制内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 10:13:18