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

Node.js如何将API返回的Buffer作为另一接口的响应返回

问题根因
  • 后端调用第三方接口拿到的result是fetch标准的Response对象,直接塞给res.send()的话,Express会自动尝试把这个对象转成JSON字符串返回,根本没有返回你要的图片buffer,还会附带很多无关的响应字段,导致浏览器拿到的响应体不是合法的二进制文件。
  • 前端看到的body stream already read报错,本质是浏览器拿到非法响应后,内部解析的时候已经消费过一次响应流,等到你手动调用response.blob()的时候流已经被锁死/读完,才会抛出这个错误。
修复代码

后端代码修复

downloadSingle = async(req, res){
try{
    // 从云存储拉取文件
    let filelist = [] // 填你实际的文件列表
    let OutputBuffers = [];

    for (let i =0; i<filelist.length; i++){
        const sFiles = await // 云存储拉取逻辑保持不变
        const sFileBuffer = await streamToBuffer(sFiles.Body)
        // 修复:原代码把fileList[i]用引号包了,导致所有文件名都是固定字符串
        OutputBuffers.push({'bufferName': filelist[i] , 'buffer': sFileBuffer})
    }
    if(OutputBuffers.length>0){
       const formData = new FormData();
       OutputBuffers.forEach(f=>{
          // 修复:原代码Buffer.form拼写错误,应为Buffer.from
          formData.append('files', Buffer.from(f.buffer), {fileName: f.bufferName})
       })
       try{
          // 调用第三方API
          const result = await fetch(`ThirdParty_API_URL`, {method: "POST", body: formData});
          if(!result.ok) {
            return res.status(result.status).json({error: '第三方接口调用失败'})
          }
          // 核心修改1:读取第三方返回的二进制内容转成Node Buffer
          const respBuffer = Buffer.from(await result.arrayBuffer())
          // 核心修改2:透传第三方返回的必要响应头,确保前端能正确解析二进制文件
          res.set({
            'Content-Type': result.headers.get('Content-Type') || 'image/png', // 可按实际情况修改兜底类型
            'Content-Disposition': result.headers.get('Content-Disposition') || 'attachment; filename="merged.png"',
            'Content-Length': respBuffer.length
          })
          // 核心修改3:直接返回二进制Buffer
          return res.send(respBuffer);
       }
       catch(e){
        return res.status(500).json({'error': e.message})
       }
    }
    return res.status(400).json({error: '没有可处理的文件'})
  }
   catch(e){
      return res.status(500).json({'error': e.message})
   }
}

前端代码优化

// 修复:原代码async语法错误,缺少参数括号
const handleDownloadEvent = async () => {
   try {
      const response = await fetch(`API_URL_for_downloadSingle`, {method: "GET"});
      if(response.ok){
         // 优化:从响应头提取文件名,没有则用兜底名称
         const fileName = response.headers.get("Content-Disposition")?.split('filename=')[1]?.replaceAll('"','') || 'merged.png';
         const blob = await response.blob();
         const url = URL.createObjectURL(blob)
         // 可选:触发浏览器下载
         const a = document.createElement('a')
         a.href = url
         a.download = fileName
         a.click()
         // 释放内存
         URL.revokeObjectURL(url)
      }
   } catch (err) {
      console.error('下载失败', err)
   }
}
额外注意点
  • 你原代码里的aysnc拼写错误、括号未闭合等低级语法问题要先修正,否则会直接导致请求异常
  • 如果后端调用第三方接口用的是Axios,直接配置responseType: 'arraybuffer'就能直接拿到Buffer,不需要额外转码,更简单
  • 不要写死Content-Type,优先透传第三方接口返回的响应头,避免不同格式图片解析失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:57:02