Nest 文件上传
Nest 文件上传主要采用 @nestjs/platform-express 提供的 Interceptor 来拦截请求并从请求中提取出文件信息传递给 Controller,如果传入 dest 选项还能将文件保存到服务端指定目录中。
本质上platform-express里的拦截器是对 multer 库的一些封装,源码中会调用 multer 的方法来实现提取文件的功能。
从单个指定字段中获取 file
typescript1 @Post('upload') 2 @UseInterceptors( 3 FileInterceptor('aaa', { 4 dest: 'uploads', 5 }), 6 ) 7 uploadFile(@UploadedFile() file: Express.Multer.File, @Body() body) { 8 console.log('body', body); 9 console.log('file', file); 10 }
从单个指定字段中获取 files
typescript1 @Post('upload') 2 @UseInterceptors( 3 FilesInterceptor('aaa', 3, { 4 dest: 'uploads', 5 }), 6 ) 7 uploadFile(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body) { 8 console.log('body', body); 9 console.log('files', files); 10 }
从多个指定字段中获取 files
typescript1 @Post('upload') 2 @UseInterceptors( 3 FileFieldsInterceptor( 4 [ 5 { name: 'aaa', maxCount: 2 }, 6 { name: 'bbb', maxCount: 2 }, 7 ], 8 { 9 dest: 'uploads', 10 }, 11 ), 12 ) 13 uploadFile(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body) { 14 console.log('body', body); 15 console.log('files', files); 16 }
自动识别带 files 的字段
typescript1 @Post('upload') 2 @UseInterceptors( 3 AnyFilesInterceptor({ 4 dest: 'uploads', 5 }), 6 ) 7 uploadFile(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body) { 8 console.log('body', body); 9 console.log('files', files); 10 }
ParseFilePipe 校验文件
typescript1 @Post('upload') 2 @UseInterceptors( 3 AnyFilesInterceptor({ 4 dest: 'uploads', 5 }), 6 ) 7 uploadFile( 8 @UploadedFiles( 9 new ParseFilePipe({ 10 validators: [ 11 new MaxFileSizeValidator({ maxSize: 1024 * 100 }), 12 new FileTypeValidator({ fileType: 'image/png' }), 13 ], 14 }), 15 ) 16 files: Array<Express.Multer.File>, 17 @Body() body, 18 ) { 19 console.log('body', body); 20 console.log('files', files); 21 }
这里主要使用两个常见的 validator:
- MaxFileSizeValidator 检验文件大小
- FileTypeValidator 校验文件类型
自定义 validator
自定义 validator 需要继承自 FileValidator
typescript1import { FileValidator } from '@nestjs/common' 2 3export class CustomFileValidator extends FileValidator { 4 constructor(options) { 5 super(options) 6 } 7 8 isValid(file: Express.Multer.File): boolean | Promise<boolean> { 9 console.log('maxSize', this.validationOptions.maxSize) 10 11 if (file.size > this.validationOptions.maxSize) { 12 return false 13 } 14 return true 15 } 16 buildErrorMessage(file: Express.Multer.File): string { 17 return `文件 ${file.originalname} 大小超出 10k` 18 } 19}
在 new ParseFilePipe的 validators 选项中使用:
typescript1 @Post('upload') 2 @UseInterceptors( 3 AnyFilesInterceptor({ 4 dest: 'uploads', 5 }), 6 ) 7 uploadFile( 8 @UploadedFiles( 9 new ParseFilePipe({ 10 validators: [new CustomFileValidator({ maxSize: 1024 * 10 })], 11 }), 12 ) 13 files: Array<Express.Multer.File>, 14 @Body() body, 15 ) { 16 console.log('body', body); 17 console.log('files', files); 18 }
总结
Nest 的文件上传是基于 multer 实现的。
Nest 对 multer 做了一层封装,提供了 FileInterceptor、FilesInterceptor、FileFieldsInterceptor、AnyFilesInterceptor 等拦截器。
这些拦截器在会拦截请求,然后从中解析出文件。
@UploadedFile或@UploadedFiles装饰器将解析后的文件传递给 handler。
在此过程中,还能使用 ParseFilePipe对文件做验证,内置了 MaxFileSizeValidator、FileTypeValidator 等 validator,也支持自定义实现。