Nestjs使用Multer上传文件
https://gabrieltanner.org/blog/nestjs-file-uploading-using-multer
本指南将向你展示如何将文件上传到你的 Nestjs 应用程序中,以及在这样做时你应该记住的事情。 您将开发一个具有三个端点的应用程序,将达到以下目的:
- 上传一个图像
- 上传多个图像
- 使用图像路径获取图像
您还将添加自定义实用工具来编辑文件名并验证图像的文件上传。 不浪费时间了,让我们开始吧。
设置
您需要做的第一件事是创建一个包含文件服务器的 Nestjs 项目。 为此,需要打开终端,执行如下命令:
这将创建一个名为 nest-file-upload 的新目录,并使用标准的 Nestjs 配置对其进行初始化。
安装好目录后,你可以使用以下命令安装应用程序所需的依赖项:
在开始编码之前,您需要做的最后一件事是创建项目所需的文件和文件夹。 这非常简单,因为应用程序只需要多一个文件。
要启动应用程序,你现在可以在你的终端中执行
上传文件
现在您已经完成了设置过程,您可以继续并开始实现实际的功能。
让我们从在你的 AppModule
中导入 MulterModule
开始,这样你就可以在其他文件中使用 Multer
。
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { MulterModule } from "@nestjs/platform-express";
@Module({
imports: [
MulterModule.register({
dest: "./files",
}),
],
controllers: [AppController],
})
export class AppModule {}
在这里,你从 @nestjs/platform-express
中导入 MulterModule
,并将其添加到 imports
语句中。
您还可以定义上传时保存文件的目的地。
Note: 这个目标从项目的根路径开始,而不是 src 文件夹。
下一步是实现实际的上传功能,这相当简单。
您只需要将 FileInterceptor()
添加到一个普通的 @Post
请求处理程序中,然后使用@UploadedFile()
装饰器从请求中提取文件。
export class AlbumController {
@Post()
@UseInterceptors(FileInterceptor("image"))
async uploadedFile(@UploadedFile() file) {
const response = {
originalname: file.originalname,
filename: file.filename,
};
return response;
}
}
FileInterceptor
接受两个参数,一个 fieldName
和一个可选的 options
对象,稍后您将使用它来检查正确的文件类型,并在目录中给文件一个自定义名称。
一次上传多个文件几乎是一样的,你只需要使用 FilesInterceptor 来代替,并传递一个额外的参数,即文件的最大数量。
export class AlbumController {
@Post("multiple")
@UseInterceptors(
FilesInterceptor("image", 20, {
storage: diskStorage({
destination: "./files",
filename: editFileName,
}),
fileFilter: imageFileFilter,
})
)
async uploadMultipleFiles(@UploadedFiles() files) {
const response = [];
files.forEach((file) => {
const fileReponse = {
originalname: file.originalname,
filename: file.filename,
};
response.push(fileReponse);
});
return response;
}
}
这很简单,这里唯一的问题是,用户可以上传所有文件类型,而不考虑文件扩展名,这并不适合所有项目,文件名只是一些随机数。
让我们通过在您的file-upload.utils.ts
文件中实现一些实用工具来修复这个问题。
首先,让我们实现只允许上传图像的文件类型过滤器。
export const imageFileFilter = (req, file, callback) => {
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
return callback(new Error("Only image files are allowed!"), false);
}
callback(null, true);
};
这里您创建了一个中间件函数,用于检查文件类型是否为图像。 如果是,它返回 true,图像将被上传,如果不是,你抛出一个错误,并为回调返回 false。
editFileName
函数具有相同的结构,但使用原始名称、文件扩展名和四个随机数创建一个自定义文件名。
export const editFileName = (req, file, callback) => {
const name = file.originalname.split(".")[0];
const fileExtName = extname(file.originalname);
const randomName = Array(4)
.fill(null)
.map(() => Math.round(Math.random() * 16).toString(16))
.join("");
callback(null, `${name}-${randomName}${fileExtName}`);
};
现在你已经创建了这两个中间件函数,是时候在 app.controller.ts
文件中使用它们了。
为此,你只需要在 FileInterceptor
中添加一个额外的配置对象,如下所示:
export class AlbumController {
@Post()
@UseInterceptors(
FileInterceptor("image", {
storage: diskStorage({
destination: "./files",
filename: editFileName,
}),
fileFilter: imageFileFilter,
})
)
async uploadedFile(@UploadedFile() file) {
const response = {
originalname: file.originalname,
filename: file.filename,
};
return response;
}
@Post("multiple")
@UseInterceptors(
FilesInterceptor("image", 20, {
storage: diskStorage({
destination: "./files",
filename: editFileName,
}),
fileFilter: imageFileFilter,
})
)
async uploadMultipleFiles(@UploadedFiles() files) {
const response = [];
files.forEach((file) => {
const fileReponse = {
originalname: file.originalname,
filename: file.filename,
};
response.push(fileReponse);
});
return response;
}
}
最后,你将添加一个@Get
路由,它将imagepath
作为参数,并使用 sendFile
方法返回图像。
export class AlbumController {
@Get(":imgpath")
seeUploadedFile(@Param("imgpath") image, @Res() res) {
return res.sendFile(image, { root: "./files" });
}
}
测试应用程序
既然您已经完成了应用程序,现在就可以通过向端点发送 HTTP 请求来测试它了。
这可以使用终端中的 curl
命令或使用一个 HTTP
客户端软件,如 Postman
或 Insomnia
来完成。
我个人使用的是《Insomnia》,但在《Postman》中也应该是一样的。
使用以下命令启动服务器:
正如终端输出所示,服务器现在运行在 http://localhost:3000
上。
要测试 API,您现在只需要创建一个新的 HTTP
请求并将请求体更改为 multipart
,这样您就可以上传文件了。
Upload images
在这里,您将目标设置为 http://localhost:3000
,并向请求体添加一个图像。
这可以通过单击复选框旁边的箭头并选择 file 来完成。
在右侧,您可以看到服务器上带有原始文件名和新文件名的响应。
Note: 稍后将使用新文件名从服务器获取图像。
Upload multiple images
在这里,您可以执行相同的操作,但要在/多个端点上上传多个文件。
Get uploaded image
获取文件也是一个简单的过程。
您只需要将从 post
请求中获得的文件名作为参数发送一个 get
请求到 API
。
项目的完整代码也可以在我的 Github 上找到。
结论
你一直坚持到最后!希望本文能帮助您理解 Nestjs
中的文件上传。
如果您觉得这很有用,请考虑推荐并与其他开发人员分享。
如果你有任何问题或反馈,请在 twitter
上告诉我或使用我的联系方式。