Nest 实现文件上传的功能

6,258 阅读2分钟

我正在参加「掘金·启航计划」

文件上传是 Web 应用程序中常见的功能之一。Nest.js 底层的 HTTP 框架是 Express,它拥有众多强大的中间件来实现各种功能。

本文将介绍如何在 Nest.js 中借助 multer 中间件来实现文件上传的功能。

multer 中间件

Multer 中间件由 Express 团队出品,专门用来处理文件上传,它与 Express 框架紧密集成,在 Nest.js 中基本上也是使用 multer 来完成文件上传的功能。

Multer 的用法非常简单,只需要简单的几行配置,就能实现文件上传的常见需求,比如限制文件类型,大小,同时支持多文件上传。

Multer 是通过解析请求的 multipart/form-data 数据,从中提取文件并将其保存到指定位置或存储系统中。它支持多种存储方式,例如本地磁盘、云存储服务等。

初始化项目

首先使用 Nest CLI 创建项目:

$ nest new nest-upload

然后进入到项目目录,安装下需要的依赖:

$ pnpm add multer
$ pnpm add -D @types/multer

@types/multer 是 multer 中间件模块的类型声明包,可以提供获更好的类型安全。

它提供了一个 Express.Multer.File 类型,表示上传的文件。

配置 Multer 中间件

从内置的 @nestjs/platform-express 导入 MulterModule 模块,它提供的 register 方法可接收一系列的选项,来完成 multer 中间件的配置。

// app.module.tsimport { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import * as path from 'path';
​
@Module({
  imports: [
    MulterModule.register({
      storage: diskStorage({
        // 指定文件存储目录
        destination: path.join(__dirname, '../uploads'),
        // 通过时间戳来重命名上传的文件名
        filename: (_, file, callback) => {
          const fileName = `${
            new Date().getTime() + path.extname(file.originalname)
          }`;
          return callback(null, fileName);
        },
      }),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

文件上传控制器

在 app.controller.ts 中,添加一个处理文件上传请求的控制器方法,使用 @Post 装饰器指定处理 POST 请求的方法,使用 @UseInterceptors@FileInterceptor 装饰器来处理文件上传。FileInterceptor 使用名称为 'file' 的字段来接收上传的文件。

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { AppService } from './app.service';
import { FileInterceptor } from '@nestjs/platform-express';
​
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}
​
  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  async uploadFile(
    @UploadedFile() file: Express.Multer.File,
  ): Promise<{ url: string }> {
    const fileUrl = await this.appService.uploadFile(file);
    return { url: fileUrl };
  }
}

该控制器方法最终返回一个包含文件 Url 的对象,响应给客户端。客户端可以通过这个 URL 去访问文件资源。

创建文件上传的服务

在 app.service.ts 中创建一个服务来处理文件上传的逻辑。

import { Injectable } from '@nestjs/common';
import { MulterDiskUploadedFiles } from '@nestjs/platform-express';
import * as path from 'path';
​
@Injectable()
export class FileUploadService {
  async uploadFile(file: Express.Multer.File): Promise<string> {
    // 到这里其实文件已经上传到服务器本地了,需要有后续的存储需求,比如要上传到云存储服务中,可以在这里继续处理
​
    // 返回文件URL
    return `http://localhost/uploads/${file.filename}`;
  }
}

测试接口

使用 ApiPost 等工具来测试一下接口,通过发送 POST 请求到 /upload 路由来测试文件上传功能。使用一个名为 'file' 的文件字段,来包含要上传的文件。

image-20230519182832616

打开本地项目的根目录,确实有一个 uploads 目录,里面存放了刚刚上传的文件:

image-20230519182953503

小结

本文简单介绍了如何在 Nest 中借助 multer 中间件来完成文件上传的功能,实现非常简单,multer 还支持多文件上传,自定义存储器等好用的功能,大家可以尝试一下。