解决Node.js stream.pipeline chunk类型错与ReadableChunk非函数报错
错误根源
- 第一个
TypeError [ERR_INVALID_ARG_TYPE]报错:stream.pipeline()要求传入的源参数必须是可读流,直接传入req.file.buffer(Buffer类型)时,Node会将Buffer作为可迭代对象逐个遍历,遍历Buffer得到的是单个字节的数值(报错中的255就是0xff字节的十进制值),而可写流仅接受string/Buffer/Uint8Array类型的写入块,因此抛出类型错误。 - 第二个
ReadableChunk is not a function报错:你提前创建了一个Readable实例赋值给ReadableChunk,调用时却把实例当成函数执行ReadableChunk(req.file.buffer),实例本身不可调用,自然触发报错;同时原自定义Readable逻辑存在两处缺陷:一是没有将传入的Buffer挂载到流实例上,二是全局复用同一个流实例会导致多次请求时流状态污染。
修复方案
最简实现(推荐)
Node.js 内置的stream.Readable.from()方法原生支持将Buffer转换为符合要求的可读流,不需要手动实现流逻辑,代码如下:
const { pipeline } = require('stream/promises'); const fs = require('fs'); const { Readable } = require('stream'); module.exports.test = async (req, res) => { const fileName = 'test.jpg'; await pipeline( Readable.from(req.file.buffer), fs.createWriteStream(`${__dirname}/../client/public/profil/${fileName}`) ); // 自行补充响应逻辑 res.send({ success: true }); }
注意:原有代码存在filename与fileName变量名大小写不一致的问题,运行时会触发变量未定义错误,需统一变量命名。
该方案完全基于内存中的Buffer做流写入,不依赖multer的磁盘存储能力,不会出现多文件上传时仅能处理2个文件的问题;多文件场景下遍历req.files数组,对每个文件的buffer执行上述写入逻辑即可。
自定义Readable实现
如果需要自定义可读流逻辑,要将流封装为工厂函数,每次调用返回新的流实例,同时正确挂载待读取的Buffer数据,正确写法如下:
const { Readable } = require('stream'); // 封装为工厂函数,接收buffer参数返回全新的可读流实例 const createBufferReadStream = (buffer) => { return new Readable({ read() { // 推送buffer内容后推送null标识读取结束,流内部会自动处理背压和分片,无需手动slice this.push(buffer); this.push(null); } }); } module.exports.test = async (req, res) => { const fileName = 'test.jpg'; await pipeline( createBufferReadStream(req.file.buffer), fs.createWriteStream(`${__dirname}/../client/public/profil/${fileName}`) ); res.send({ success: true }); }
注意:不要全局复用同一个可读流实例,流读取完成后会进入已结束状态,无法二次使用,每个文件写入任务都必须创建新的流实例。
内容的提问来源于stack exchange,提问作者user10863293
相关产品推荐
相关产品推荐

