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_
相关产品推荐
相关产品推荐

