前言
这篇文章是作者个人学习NestJS的产出,参考了小满ZS的Nest教程
后端实现
为了实现上传静态资源图片的功能,一共要经历四步:
- 安装中间件
multer
- 配置
Multer
- 创建上传接口
- 配置静态资源目录
安装中间件multer
Multer是Node.js的中间件,用于处理multipart/form-data
类型的数据,主要用于上传文件,包括视频、图片等。
其中,multipart/form-data
是一种HTTP请求的编码类型,适合传输包含文件的表单数据,允许将表单信息分为多个部分,每个部分都可以有自己的内容类型。这使得其可以同时发送文本字段和文件数据,非常适合文件上传的场景。
multer可以通过以下指令安装
npm i multer
为了获取ts的类型推断,安装multer的ts包,这个包只需在生产环境用到,因此加上-D
npm i @types/multer -D
配置Multer
Multer有四个基本设置:
- diskStorage:控制文件的存储方式,存储到磁盘里,可定义文件的储存路径和文件名
- memoryStorage:控制文件的储存方式,储存到内存中,适用于临时文件处理
- limits:定义上传文件的大小限制
- fileFilter:根据文件类型,过滤文件
下面给出Multer在NestJS里的配置
import { Module } from '@nestjs/common';
import { UplodeService } from './uplode.service';
import { UplodeController } from './uplode.controller';
//导入MulterModule,用来在NestJS里注册模块
import { MulterModule } from '@nestjs/platform-express';
//导入multer库的diskStorage,用来配置文件存储方式
import { diskStorage } from 'multer';
//导入path模块的extname和join函数,用来处理文件路径和文件名
//extname()用来获取文件的扩展名,如.jpg、.png等
//join()用来将两个路径合并
import { extname, join } from 'path';
@Module({
//在Module的imports数组里,注册并配置Multer模块
//调用MulterModule的register()方法进行配置,传入配置对象
imports: [MulterModule.register({
//配置项的storage属性决定文件的储存位置和方式
//通过multer模块的diskStorage来进行配置,表示文件存入磁盘,传入配置对象
storage: diskStorage({
//destination配置文件上传后的路径
//__dirname是全局变量,表示当前文件目录。假设index.js文件在/home/ubuntu/index.js这里,那么
//__dirname表示:/home/ubuntu
//path模块的join()函数,用来合并两个目录。
//拿上面的例子距离,合并后的路径为:/home/images
//因为../images表示上一级目录的images文件夹
destination: join(__dirname, "../images"),
//定义文件名,这里通过函数来决定文件的名字
//这个函数传入三个参数:request、file对象和callback函数
//callback函数接收两个参数:错误对象和文件名。如果没有错误通常传入null
//callback函数用来通知multer,文件命名已经完成了,如果没有错误的话可以进行下一步操作了
filename: (_, file, callback) => {
//这里的文件名为字符串,具体是:当前时间的时间戳 + 文件扩展名
const fileName = `${new Date().getTime() + extname(file.originalname)}`
return callback(null, fileName)
}
})
})],
controllers: [UplodeController],
providers: [UplodeService],
})
export class UplodeModule { }
创建上传接口
现在我们配置好了multer,将上传的文件存储到磁盘里,并且指定了存放上传文件的文件目录,规定了上传文件的文件名。
现在我们需要实现一个上传接口,我们将上传功能单独看作是一个模块,因此我们先通过脚手架创建新的模板
nest g source upload
选择RESTful风格
然后我们在upload.controller中开始编写上传接口
import { Controller, Post } from '@nestjs/common';
import { UplodeService } from './uplode.service';
//导入UseInterceptor装饰器和UploadedFile装饰器
//UseInterceptor用于在Controller中应用拦截器,而UploadedFile用于获取上传的文件
import { UseInterceptors, UploadedFile } from '@nestjs/common';
//导入FileInterceptor,是一个处理文件上传的拦截器
import { FileInterceptor } from '@nestjs/platform-express';
//定义路径为/upload
@Controller('upload')
export class UplodeController {
constructor(private readonly uplodeService: UplodeService) { }
//指定接口为Post方法,路径为/upload/pic
@Post("pic")
//使用@UseInterceptors()装饰器来应用FileInterceptor拦截器,拦截名字为file的上传文件
@UseInterceptors(FileInterceptor("file"))
//通过@UploadedFile()装饰器,来从request请求中提取出上传的文件
upload (@UploadedFile() file){
//对文件的处理逻辑
console.log(file)
return true
}
}
看到这里,你是否和我有一样的疑惑: 怎么突然就有了file对象?这个file对象是个啥?
别着急!下面我们一起深挖这段multer处理文件的逻辑
首先可以确定的是,在console.log(file)
这一段,我们以及获取到了文件,并且可以操作文件了。这个时候用户上传的文件,已经被保存到了目标文件夹中。所以将文件保存到服务器的过程,一定发生在获取到file对象之前。
所以,将上传的文件保存到服务器中,是装饰器完成的。更具体地说是使用@UseInterceptors()装饰器来应用FileInterceptor拦截器的时候。
当使用FileInterceptor
拦截器时,会首先处理文件上传流程,然后将文件保存到指定目录,然后按照配置重命名文件。在这些工作完成后,拦截器再将文件对象传递给upload(@UploaderFile() file)
方法中,其中的file参数已经是处理后的文件对象了。
配置静态目录
既然是上传静态资源,我们可以配置静态目录,通过添加前缀,让用户可以通过统一的入口去获取到静态资源
静态目录的配置在main.ts中实现
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';
//导入session
import * as session from "express-session";
//由于multer是express的插件,为了可以在NestJS中使用,需要导入NesrExpressApplication,这时express平台的应用接口
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from "path"
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.enableVersioning({
type: VersioningType.URI
})
//注册使用
app.use(session({
secret: "Icicle_Crino",
name: "Crino",
}))
//生成静态目录,通过useStaticAssets()来定义静态目录
//上文讲到过,join()是path模块的方法,用于合并两个路径
//join(__dirname, "images") __dirname是全局变量,表示当前文件所在目录
//join()最后返回的是:当前路径下的/images文件夹
app.useStaticAssets(join(__dirname, "images"), {
//前缀名,意味着images文件夹下的资源,可以通过/Crino前缀访问,如
//http://localhost:3000/Crino/1714551064615.jpg
prefix: "/Crino"
})
await app.listen(3000);
}
bootstrap();
总结
到这里我们就完成了通过NestJS实现静态资源上传的全过程。一共分为四步:
- 安装中间件
multer
- 配置
Multer
- 创建上传接口
- 配置静态资源目录
作者也是刚刚开始学习NestJS新手,如果文章中存在错误或笔误的地方,欢迎和谐讨论交流~ 如果大家想看的话,作者后续会更新前端教程,教你在前端如何实现文件上传功能
最后祝大家五一快乐