Node.js 18.12中ReadableStream pipeTo写入本地文件失败求助
解决Node.js 18.12中GraphQL Yoga 3返回的ReadableStream写入本地文件的问题
错误原因
GraphQL Yoga 3返回的是Web标准的ReadableStream(遵循WHATWG规范),而fs.createWriteStream生成的是Node.js原生可写流,两者API体系不兼容。Web流的pipeTo方法仅接受Web标准的WritableStream,直接传入Node.js写流就会触发你遇到的类型错误。
可行解决方案
方案1:将Node.js写流转为Web标准WritableStream
Node.js 18+的原生流自带toWeb()方法,能把Node.js写流转换成Web标准的WritableStream,完美适配Web ReadableStream的pipeTo:
const fs = require('fs'); const path = require('path'); const outputPath = path.join(__dirname, 'test.png'); const nodeWriteStream = fs.createWriteStream(outputPath); // 转换为Web标准可写流 const webWriteStream = nodeWriteStream.toWeb(); // stream 是GraphQL Yoga返回的Web ReadableStream await stream.pipeTo(webWriteStream); console.log('DONE');
方案2:将Web ReadableStream转为Node.js可读流
如果方案1遇到实例兼容性问题(比如第三方库实现的Web流不被Node.js识别),可以把Web流转成Node.js原生可读流,再用Node.js的pipe方法:
const fs = require('fs'); const path = require('path'); const { Readable } = require('stream'); const outputPath = path.join(__dirname, 'test.png'); const writeStream = fs.createWriteStream(outputPath); // 转换Web流为Node.js可读流 const nodeReadable = Readable.fromWeb(stream); // 使用Node.js原生pipe写入 nodeReadable.pipe(writeStream).on('finish', () => { console.log('DONE'); });
方案3:手动读取Web流内容写入文件
如果前两种方案都失效,直接手动读取Web流的所有数据块,再一次性写入文件:
const fs = require('fs').promises; const path = require('path'); const outputPath = path.join(__dirname, 'test.png'); const reader = stream.getReader(); const chunks = []; let readResult; // 逐块读取Web流内容 while (!(readResult = await reader.read()).done) { chunks.push(readResult.value); } // 合并数据块并写入文件 await fs.writeFile(outputPath, Buffer.concat(chunks)); console.log('DONE');
你尝试过的方法为什么失败
new Readable().wrap(stream):这个方法是专门用来兼容Node.js v0.10之前的旧式流,完全不支持Web标准的ReadableStream,自然会报stream.on is not a function(Web流没有Node.js流的on事件方法)。Readable.fromWeb(stream):大概率是因为GraphQL Yoga返回的Web流由第三方库(如undici、@whatwg-node/fetch)实现,虽然符合Web标准,但Node.js的Readable.fromWeb对实例构造函数的检查过于严格,导致识别失败。这种情况下优先用方案1或方案3。
内容的提问来源于stack exchange,提问作者Martin Cup
相关产品推荐
相关产品推荐

