如何将Express.Multer.File转换为ReadStream适配Bunny.Net上传?
NestJS中视频上传:将Multer的File转换为Bunny.Net所需的ReadStream
问题描述
在NestJS项目实现视频上传时,Bunny.Net封装库的createAndUploadVideo方法要求传入ReadStream类型参数,但通过Multer获取的Express.Multer.File仅提供buffer和stream属性。由于文件未落地,无法使用fs.createReadStream(需要文件路径),需将buffer或stream转换为ReadStream。
控制器代码
@ApiUpload('', { useAuthGuard: false, description: 'Upload file - max 25mb', type: OutputFileDto }) async create(@User() user: UserEntity, @UploadedFile() uploadedFile: Express.Multer.File) { return this._fileService.create(user, uploadedFile); }
项目启动代码
async function bootstrap() { const app = await NestFactory.create(AppModule); const configService: ConfigService<IConfiguration> = app.get(ConfigService); // generate REST API documentation const documentation = new DocumentBuilder().setTitle('API documentation').setVersion('1.0'); documentation.addBearerAuth(); SwaggerModule.setup( '', app, SwaggerModule.createDocument(app, documentation.build(), { extraModels: [], }), ); // interceptors app.useGlobalInterceptors(new LoggerInterceptor()); // validate DTOs app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); // handle unique entities error from database const { httpAdapter } = app.get(HttpAdapterHost); app.useGlobalFilters(new QueryErrorFilter(httpAdapter)); // enable cors app.enableCors(); // raw body app.use( json({ limit: '1mb', verify: (req: IncomingMessage, res: ServerResponse, buf: Buffer, encoding: BufferEncoding) => { if (buf && buf.length) { req['rawBody'] = buf.toString(encoding || 'utf8'); } }, }), ); // security app.use(helmet()); app.use( rateLimit({ windowMs: 900000, max: 50099, message: { status: 429, message: 'Too many requests, please try again later.' }, }), ); await app.listen(configService.get('basic.port', { infer: true })); } bootstrap();
服务层create方法代码
async create(user: UserEntity, uploadedFile: Express.Multer.File) { let url: string = ''; let storageKey: string = ''; let length: number | undefined; console.log(uploadedFile); if (['video/mp4'].includes(uploadedFile.mimetype)) { const stream = new BunnyCdnStream({ videoLibrary: '...', apiKey: '...', }); const readable = Readable.from(uploadedFile.buffer); console.log(readable); const video = await stream.createAndUploadVideo(readable, { title: '' }); } else { storageKey = `files/${new Date().getTime()}-${slugify(uploadedFile.originalname)}`; url = await this._uploadService.save(storageKey, uploadedFile.buffer, uploadedFile.mimetype); } if (!url) { throw new BadRequestException(ErrorMessages.FILE_UPLOAD_FAILED); } return this._fileRepository.save( new FileEntity({ originalname: uploadedFile.originalname, mimetype: uploadedFile.mimetype, size: uploadedFile.size, url, storageKey, user, length, }), ); }
解决方案
你的方案的正确性
你使用Readable.from(uploadedFile.buffer)的方式是完全可行且正确的。Node.js的stream.Readable.from()方法可以直接将Buffer转换为符合要求的Readable流,能够被Bunny.Net的createAndUploadVideo方法正常消费。
更优方案:直接复用Multer的stream属性
Express.Multer.File本身自带的stream属性就是一个Readable流,你可以直接传入该属性,无需额外转换:
const video = await stream.createAndUploadVideo(uploadedFile.stream, { title: '' });
这种方式更高效,因为它直接复用了Multer处理上传时的原始流,避免了将Buffer重新转换为流的内存开销,尤其适合大文件上传场景。
注意事项
- 若使用
uploadedFile.stream,需确保Multer的配置不会提前将文件全部缓存到内存(默认情况下,Multer对小于1MB的文件会存到内存,大于则写入临时文件,但无论哪种情况,stream属性都可正常使用)。 - 无论采用哪种方式,都要确保流被正确消费,避免出现内存泄漏问题。
内容的提问来源于stack exchange,提问作者Korer
相关产品推荐
相关产品推荐

