likes
comments
collection
share

nestJS系列--图片上传

作者站长头像
站长
· 阅读数 25

前言

文件上传是每个项目都会用到的功能,NestJS在实现文件上传时,有TypeScript的强类型优势,确保代码安全稳定;语法十分的简洁,装饰器API如@UploadedFile()简化上传逻辑;支持自定义中间件增强功能,如验证和转换;其性能出色,尤其适合高并发场景;并且,NestJS与云存储服务的友好集成,使文件管理更加便捷;丰富的插件生态系统提供了更多扩展可能,进一步优化了开发体验。这些特点使得NestJS成为实现高效、安全文件上传的理想选择。

简单的文件上传

  • 执行指令:nest g res uploads --no-spec, 一直按回车键
  • 安装 Multer typings 包:npm i -D @types/multer, 这样就可以有类型支持了

在uploads/uplods.controller.ts中将代码修改如下

import {
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UploadsService } from './uploads.service';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('uploads')
export class UploadsController {
  constructor(private readonly uploadsService: UploadsService) {}

  @Post()
  @UseInterceptors(FileInterceptor('file', { dest: 'uploads' }))
  upload(@UploadedFile() file: Express.Multer.File) {
    console.log(file.path);
    return 0;
  }
}

@UseInterceptors: 使用拦截器,里面传一个拦截器函数就行了 @@UseInterceptors: 文件拦截器第一个参数是字段名第二参数是一个对象,dest是文件存放的位置,这个文件夹会自动创建。

我们在apifox里面测试一下:

nestJS系列--图片上传 nestJS系列--图片上传

可见已经正确的将文件的路径打印出来了。至此简单的文件上传已经完成了。

文件验证

只允许图片上传

实现

将代码修改如下:

import {
  BadRequestException,
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UploadsService } from './uploads.service';
import { FileInterceptor } from '@nestjs/platform-express';
import * as path from 'path';

@Controller('uploads')
export class UploadsController {
  constructor(private readonly uploadsService: UploadsService) {}

  @Post()
  @UseInterceptors(
    FileInterceptor('file', {
      dest: 'uploads',
      fileFilter(request, file, cal) {
        const ext = path.extname(file.originalname);
        if (['.jpg', '.png', '.jpeg'].includes(ext)) {
          return cal(null, true);
        } else {
          return cal(new BadRequestException('文件格式错误'), false);
        }
      },
    }),
  )
  upload(@UploadedFile() file: Express.Multer.File) {
    console.log(file.path);
    return 0;
  }
}
nestJS系列--图片上传

以上代码中新增了一个fileFilter函数,里面的参数主要看filecal, file就是传来的文件cal就是一个回调函数,如果ext在定义的文件后缀的数组中的时候第一个参数是null第二个参数是true否则第一个参数是一个异常对象第二个参数是false。

在apifox里面测试一下,这里我先上传一个压缩文件

nestJS系列--图片上传 nestJS系列--图片上传 显然返回报错信息了

试一下图片就正常返回了

nestJS系列--图片上传

可见我们的文件类型校验生效了,但是在装饰器里面写这么一坨校验的代码实在是不够美观,而且复用性也不强,我们可以封装一个聚合装饰器。

代码改造

创建custom-dec/custom.decorator.ts,新增如下代码:

import { Controller, Post, UploadedFile } from '@nestjs/common';
import { UploadsService } from './uploads.service';
import { FileUpload } from 'src/custom-dec/custom.decorator';

@Controller('uploads')
export class UploadsController {
  constructor(private readonly uploadsService: UploadsService) {}

  @FileUpload(['.jpeg', '.png'])
  @Post()
  upload(@UploadedFile() file: Express.Multer.File) {
    console.log(file.path);
    return 0;
  }
}

这段代码看似很多其实就是之前UseInterceptors装饰器整个剪切过来直接当参数放在applyDecorators函数里面,然后在外面套一个FileUpload函数,这个函数名随意,参数是文件类型,返回了applyDecorators执行结果。

改造upload路由

import { Controller, Post, UploadedFile } from '@nestjs/common';
import { UploadsService } from './uploads.service';
import { FileUpload } from 'src/custom-dec/custom.decorator';

@Controller('uploads')
export class UploadsController {
  constructor(private readonly uploadsService: UploadsService) {}

  @FileUpload(['.jpeg', '.png'])
  @Post()
  upload(@UploadedFile() file: Express.Multer.File) {
    console.log(file.path);
    return 0;
  }
}
nestJS系列--图片上传

这里将之前的UseInterceptors装饰器改成了我们自定义的聚合装饰器,并且文件类型自定义穿进去。 在apifox里面测试一下,先用不是图片的文件:

nestJS系列--图片上传

上传一个图片:

nestJS系列--图片上传

可见改造之后的代码是没有问题的,并且理由部分的代码简洁了许多。

图片大小限制

很简单,就是增加一个属性,这里限制最大为10m

nestJS系列--图片上传 由于我没有比10m大的图片所以我把图片类型限制去掉,上传一个压缩包发现大小限制生效了,在apifox里测试一下: nestJS系列--图片上传
转载自:https://juejin.cn/post/7377664582730579987
评论
请登录