NestJS17-File upload

处理文件上传,Nest提供了基于express的multer包的内置模块。Multer处理multipart/form-data类型的数据,它主要通过HTTPPOST请求来上传文件。这个模块完全可以配置并且您可以调整它的行为来符合您的项目需求。

警告

Multer不能处理不支持multipart/form-data形式的数据 并且,这个包也不能和FastifyAdapter一起使用

为了更好的类型安全,让我们来安装Multer类型包

bash 复制代码
$ npm i -D @types/multer

当这个包安装后,我们现在可以使用Express.Multer.File类型(您可以通过这个方法来导入:import { Express } from 'express'

基本例子

上传单个文件,简单的将Fileintreceptor()拦截器绑定到路由句柄并且使用@UploadedFile()装饰器从request中取得file文件。

ts 复制代码
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
  console.log(file);
}

注意

FileInterceptor()装饰器从@nestjs/platform-express包导入。@UploadedFile()装饰器从@nestjs/common包导入。

FileInterceptor()装饰器有2个参数

  • fieldName:提供包含文件的HTML表单中字段名称的字符串
  • options:MulterOptions类型的可选对象。和multer构造器中使用的是同一个对象(更多

警告

FileInterceptor()可能与Google Firebase或其他第三方云提供商不兼容。

文件检查

许多时候都能很有效的检查进来的文件元数据,比如文件大小或者文件的mime-type。您能够创建您自制的管道并且和有UploadedFile装饰器的参数绑定。下面的例子演示了如何通过管道验证文件的基本大小:

ts 复制代码
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';

@Injectable()
export class FileSizeValidationPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    // "value"是一个包含文件属性和元数据的对象
    const oneKb = 1000;
    return value.size < oneKb;
  }
}

Nest提供了内置管道来处理共通用例并促进/规范新增。这个管道叫做ParseFilePipe,如下:

ts 复制代码
@Post('file')
uploadFileAndPassValidation(
  @Body() body: SampleDto,
  @UploadedFile(
    new ParseFilePipe({
      validators: [
        // ... Set of file validator instances here
      ]
    })
  )
  file: Express.Multer.File,
) {
  return {
    body,
    file: file.buffer.toString(),
  };
}

如您所见,它需要特定一个文件验证的数组将会被ParseFilePipe执行。我将会讨论验证的接口,但是值得注意的是这个管道还有2个附加可选参数:

参数 说明
errorHttpStatusCode HTTP状态码将会因为任何的验证失败而被抛出
exceptionFactory 一个工厂它将会收到异常消息并返回一个异常

现在,回到FileValidator接口。为了让管道结合验证,您需要既使用内置实现又要提供您自己定义的FileValidator。看下例子:

ts 复制代码
export abstract class FileValidator<TValidationOptions = Record<string, any>> {
  constructor(protected readonly validationOptions: TValidationOptions) {}

  /**
   * 指示根据构造函数中传递的选项,是否应将此文件视为有效文件。
   * @param file请求对象中的文件
   */
  abstract isValid(file?: any): boolean | Promise<boolean>;

  /**
   * 在验证失败时生成错误消息。
   * @param file请求对象中的文件
   */
  abstract buildErrorMessage(file: any): string;
}

注意

FileValdator接口通过它的isValid方法提供异步验证。要利用类型安全性,还可以将file参数为Express.Multer.File类型,以防您使用express(默认)作为驱动程序。

FileValidator是一个通常的类它访问文件对象并且根据服务端提供的参数验证它。Nest有2个内置FileValidator实现您能在您的项目中使用:

  • MaxFileSizeValidator - 验证是否取得文件的大小小于提供的值(用bytes比较)
  • FileTypeValidator - 验证是否文件的mime-type类型符合提供的值

警告

为了验证文件类型,FileTypeValidator类使用multer检测到的类型。默认情况下,multer从用户设备上的文件扩展名推断文件类型。然而,它不会检查实际的文件内容。由于文件可以被重命名为任意扩展名,如果您的应用程序需要更安全的解决方案,考虑使用自定义实现(比如检查文件的magic number)。

为了明白这些如何能够结合上文FileParsePipe一起使用,我们将使用上一个示例中呈现的代码片段的修改版本:

ts 复制代码
@UploadedFile(
  new ParseFilePipe({
    validators: [
      new MaxFileSizeValidator({ maxSize: 1000 }),
      new FileTypeValidator({ fileType: 'image/jpeg' }),
    ],
  }),
)
file: Express.Multer.File,

注意

如果验证器的数量大幅增加或它们的选项使文件变得混乱,您可以将这个数组定义在一个单独的文件中,然后将其作为一个名为fileValidators的命名常量导入到这里

最终,您可以使用特殊的ParseFilePipeBuilder类它允许您组合和构建您的验证器。通过如下所示的方式使用它,您可以避免手动实例化每个验证器,并直接传递它们的选项:

ts 复制代码
@UploadedFile(
  new ParseFilePipeBuilder()
    .addFileTypeValidator({
      fileType: 'jpeg',
    })
    .addMaxSizeValidator({
      maxSize: 1000
    })
    .build({
      errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
    }),
)
file: Express.Multer.File,

文件数组

为了上传文件数组(验证单个项目名),使用FileInterceptor()装饰器。这个装饰器有2个参数。

  • uploadedFields:一个对象数组,每个对象需要一个字符串值的项目名的name属性,一个可选maxCount属性。
  • options:可选的MulterOptions对象。

当使用FileFieldsInterceptor(),从@UploadedFiles()装饰器的request中取得文件(files)。

ts 复制代码
@Post('upload')
@UseInterceptors(FileFieldsInterceptor([
  { name: 'avatar', maxCount: 1 },
  { name: 'background', maxCount: 1 },
]))
uploadFile(@UploadedFiles() files: { avatar?: Express.Multer.File[], background?: Express.Multer.File[] }) {
  console.log(files);
}

任何文件

要上传带有任意字段名键的所有字段,请使用AnyFilesInterceptor()装饰器。此装饰器可以接受一个可选的options对象,如上所述。

当使用AnyFilesInterceptor()时,使用@UploadedFiles()装饰器从request中提取文件。

ts 复制代码
@Post('upload')
@UseInterceptors(AnyFilesInterceptor())
uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) {
  console.log(files);
}

没有文件

要接受multipart/form-data但不允许上传任何文件,请使用NoFilesInterceptor。这会将多部分数据设置为请求主体的属性。如果请求中包含文件,它们将引发一个BadRequestException异常。

ts 复制代码
@Post('upload')
@UseInterceptors(NoFilesInterceptor())
handleMultiPartData(@Body() body) {
  console.log(body)
}

默认参数

您可以按照上述说明在文件拦截器中指定multer选项。要设置默认选项,您可以在导入MulterModule时调用静态的register()方法,传递支持的选项。您可以使用列在此处的所有选项。

ts 复制代码
MulterModule.register({
  dest: './upload',
});

提示

MulterModule类是从@nestjs/platform-express包导出的

异步配置

当您需要异步设定MulterModules参数来代替静态的配置,使用registerAsync()方法。和大多数动态模块一样,Nest提供了几个技术来处理异步配置

一个技术就是使用工厂模式:

ts 复制代码
MulterModule.registerAsync({
  useFactory: () => ({
    dest: './upload',
  }),
});

和其他的factory providers一样,我们的工厂函数可以是异步的能够通过inject注入依赖

ts 复制代码
MulterModule.registerAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    dest: configService.get<string>('MULTER_DEST'),
  }),
  inject: [ConfigService],
});

或者,您可以使用类来代替工厂用于配置MulterModule,如下:

ts 复制代码
MulterModule.registerAsync({
  useClass: MulterConfigService,
});

上述结构在MulterModule内部实例化MulterConfigService,使用它来创建所需的选项对象。请注意,在此示例中,MulterConfigService必须实现MulterOptionsFactory接口,如下所示。MulterModule将在提供的类的实例化对象上调用createMulterOptions()方法。

ts 复制代码
@Injectable()
class MulterConfigService implements MulterOptionsFactory {
  createMulterOptions(): MulterModuleOptions {
    return {
      dest: './upload',
    };
  }
}

如果您想要重用现有的选项提供程序,而不是在MulterModule内部创建一个私有副本,可以使用useExisting语法。

ts 复制代码
MulterModule.registerAsync({
  imports: [ConfigModule],
  useExisting: ConfigService,
});
相关推荐
并不会41 分钟前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
悦涵仙子43 分钟前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
衣乌安、44 分钟前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜44 分钟前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师1 小时前
CSS的三个重点
前端·css
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie4 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿5 小时前
webWorker基本用法
前端·javascript·vue.js