环境配置
为了处理理文件上传,Nest 提供了一个基于 Express 的 multer 中间件包的内置模块。Multer 处理以该格式发布的数据,主要用于通过 HTTP 请求上传文件。此模块是完全可配置的。
所需依赖包如下:
pnpm add multer pnpm add -D @types/multer
上传配置可以放在控制器方法,也可以放在模块中,下面是在模块中定义。
模块配置
首先创建一个crud模板
在upload.module.ts模块中引入这些配置
import { Global, Module } from '@nestjs/common' import { MulterModule } from '@nestjs/platform-express' import { diskStorage } from 'multer' import { extname } from 'path' import { UploadController } from './upload.controller' import { UploadService } from './upload.service' @Global() @Module({ imports: [ MulterModule.registerAsync({ useFactory() { return { storage: diskStorage({ //文件储存位置 destination: 'uploads', //文件名定制 filename: (req, file, callback) => { const path = Date.now() + '-' + Math.round(Math.random() * 1e10) + extname(file.originalname) callback(null, path) }, }), } }, }), ], controllers: [UploadController], providers: [UploadService] }) export class UploadModule { }
这里我们是在upload模块中注册了MulterModule模块,异步注册后,通过工厂函数的方式对上传的文件进行了定制化配置,这里的格式是日期+随机数+文件拓展名的方式
controller使用
接着在控制器中使用,要上传单个文件,只需将拦截器绑定到路由处理程序,然后使用装饰器从中提取。拦截器后面再具体讲解,它其实就是在访问路由前后对数据进行的处理。
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common' import { FileInterceptor } from '@nestjs/platform-express' @Controller('upload') export class UploadController { @Post('image') @UseInterceptors(FileInterceptor('file')) image(@UploadedFile() file: Express.Multer.File) { return file } }
我们可以测试一下,能够得到文件的具体信息
FileInterceptor配置
我们这里用到的拦截器FileInterceptor()它有两个参数
fileName: 提供保存文件的 HTML 表单中的字段名称的字符串
options: 类型的可选对象,与 multer 构造函数使用的对象相同,主要可以配置上传文件的大小之类的
我们给展开写写看看
import { Controller, MethodNotAllowedException, Post, UploadedFile, UseInterceptors } from '@nestjs/common' import { FileInterceptor } from '@nestjs/platform-express' @Controller('upload') export class UploadController { @Post('upload') @UseInterceptors(FileInterceptor('file', { limits: { fileSize: Math.pow(1024, 2) * 2 }, fileFilter(req: any, file: Express.Multer.File, callback: (error: Error | null, acceptFile: boolean) => void) { if (!file.mimetype.includes('image')) { callback(new MethodNotAllowedException('类型不支持'), false) } else { callback(null, true) } } })) image(@UploadedFile() file: Express.Multer.File) { return file } }
里面的配置项,第一个是限制文件大小,第二个是一个函数,用来限制文件类型的
limits: 对文件大小,文件名大小等限制
fileFilter()对文件类型验证的函数
filterFile接受三个参数:
req:请求对象
file: 上传的文件,进行类型判断的
callback: 回调函数,用于返回验证结果 第一个参数位null或者error 第二个参数acceptFile 一个布尔值 。
当上传的文件类型满足有image时返回null,acceptFile返回true
否则返回一个error以及false
当我上传一个不是图片类型(jpg png webp gif jpeg等)的文件时 会报类型错误
如果上传分图片/文档等不同类型的上传处理,使用上面的方式需要在控制器的不同方法定义重复度很高的代码 。下面我们来简化这个过程。
优化代码
聚合装饰器
我们将 @UseInterceptors(FileInterceptor('file')) 通过装饰器聚合来简化代码,下面在 ./upload.ts 文件中定义。
import { applyDecorators, UseInterceptors } from '@nestjs/common' import { FileInterceptor } from '@nestjs/platform-express' import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface' export function upload(fieldName = 'file', options: MulterOptions = {}) { return applyDecorators(UseInterceptors(FileInterceptor(fieldName, options))) }
这样在controller中可以这样直接用@upload就可以将之前那一堆东西简化
抽离代码封装
在./upload.ts中将fileFilter封装起来让上传的文件类型更加灵活
import { applyDecorators, UnsupportedMediaTypeException, UseInterceptors } from '@nestjs/common' import { FileInterceptor } from '@nestjs/platform-express' import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface' export function upload(fieldName = 'file', options: MulterOptions = {}) { return applyDecorators(UseInterceptors(FileInterceptor(fieldName, options))) } export function fileMimetypeFilter(...mimes: string[]) { return (req: any, file: Express.Multer.File, callback: (error: Error | null, acceptFile: boolean) => void) => { if (mimes.some(mime => file.mimetype.includes(mime))) { callback(null, true) } else { callback(new UnsupportedMediaTypeException('文件类型错误'), false) } } }
在controller中使用
到这里基本已经结束了,但是对代码封装的更深一点,我们可以对每种上传的文件进行一次封装
在controller中使用 这样一看是不是代码简洁多了
写在最后
nest.js的文件乍一看确实吓人,配置文件很多,学知识就像谈恋爱,要慢慢来,多看文档,多敲代码 官方文档很给力,希望能够帮助到大家!