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

如何用Node.js不使用.then语法实现媒体文件跨服务器管道传输

Node.js 流式传输媒体文件方案(从file-server到file-receiver)

方案一:原生http模块 + Async/Await + 流式管道

原生HTTP请求返回的响应本身就是可读流,天然支持管道操作,通过Promise封装配合async/await可完全避免.then链式调用。

const http = require('http');
const { pipeline } = require('stream/promises'); // Node.js 15+ 提供,自动处理流的背压与资源清理

// 从file-server获取文件可读流
async function getFileStream(fileServerUrl) {
  return new Promise((resolve, reject) => {
    const req = http.get(fileServerUrl, (res) => {
      if (res.statusCode !== 200) {
        reject(new Error(`获取文件失败:${res.statusCode}`));
        return;
      }
      resolve(res);
    });
    req.on('error', reject);
  });
}

// 上传可读流到file-receiver
async function uploadStream(fileStream, receiverUrl) {
  return new Promise((resolve, reject) => {
    const uploadReq = http.request(receiverUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/octet-stream', // 根据实际媒体类型调整
      }
    }, (res) => {
      res.statusCode >= 200 && res.statusCode < 300 
        ? resolve(res.statusCode) 
        : reject(new Error(`上传失败:${res.statusCode}`));
    });

    uploadReq.on('error', reject);
    // 使用pipeline替代直接pipe,更安全地处理流传输
    pipeline(fileStream, uploadReq, (err) => err && reject(err));
  });
}

// 主流程
async function transferMedia(fileServerUrl, receiverUrl) {
  try {
    const fileStream = await getFileStream(fileServerUrl);
    await uploadStream(fileStream, receiverUrl);
    console.log('文件传输完成');
  } catch (err) {
    console.error('传输出错:', err);
  }
}

// 调用示例
transferMedia('http://file-server/path/to/media', 'http://file-receiver/upload');

方案二:node-fetch + Async/Await + 流式传输

如果习惯使用Fetch API,node-fetch的响应对象body属性是可读流,可转换为Node.js流后进行管道操作。

const fetch = require('node-fetch');
const { pipeline } = require('stream/promises');
const http = require('http');

async function transferMedia(fileServerUrl, receiverUrl) {
  try {
    // 从file-server获取流式响应
    const fileRes = await fetch(fileServerUrl, { method: 'GET' });
    if (!fileRes.ok) throw new Error(`获取文件失败:${fileRes.status}`);

    // 创建上传请求
    const uploadReq = http.request(receiverUrl, {
      method: 'POST',
      headers: {
        'Content-Type': fileRes.headers.get('content-type') || 'application/octet-stream',
        'Content-Length': fileRes.headers.get('content-length')
      }
    });

    // 执行流式传输
    await pipeline(fileRes.body, uploadReq);

    // 校验上传结果
    const uploadRes = await new Promise(resolve => uploadReq.on('response', resolve));
    if (!(uploadRes.statusCode >= 200 && uploadRes.statusCode < 300)) {
      throw new Error(`上传失败:${uploadRes.statusCode}`);
    }

    console.log('文件传输完成');
  } catch (err) {
    console.error('传输出错:', err);
  }
}

// 调用示例
transferMedia('http://file-server/path/to/media', 'http://file-receiver/upload');

方案三:got库简化流式操作

got库原生支持流式API,代码更简洁,无需手动封装Promise。

const got = require('got');
const { pipeline } = require('stream/promises');

async function transferMedia(fileServerUrl, receiverUrl) {
  try {
    // 获取文件可读流
    const fileStream = got.stream(fileServerUrl);
    // 创建上传可写流
    const uploadStream = got.stream.post(receiverUrl, {
      headers: {
        'Content-Type': 'application/octet-stream'
      }
    });

    // 动态获取原文件的Content-Type(可选)
    fileStream.on('response', res => {
      uploadStream.setHeader('Content-Type', res.headers['content-type']);
    });

    // 执行传输
    await pipeline(fileStream, uploadStream);
    console.log('文件传输完成');
  } catch (err) {
    console.error('传输出错:', err);
  }
}

// 调用示例
transferMedia('http://file-server/path/to/media', 'http://file-receiver/upload');

方案选择建议

  • 原生模块方案:无额外依赖,适合轻量场景,兼容性最好
  • node-fetch方案:适配Fetch API习惯,需额外安装依赖
  • got方案:API简洁,开发效率高,适合快速实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:52:01