文件上传以及 Swagger NestJs 中的其他数据

Jam*_*riq 1 nestjs nestjs-swagger

我想将文件与 JSON 一起发送

{
    "comment" : "string",
    "outletId" : 1
}
Run Code Online (Sandbox Code Playgroud)

我从文档中得到的帮助是

requestBody:
    content:
      multipart/form-data:
        schema:
          type: object
          properties:
            orderId:
              type: integer
            userId:
              type: integer
            fileName:
              type: string
              format: binary
Run Code Online (Sandbox Code Playgroud)

我不知道把这个架构放在哪里。我曾尝试将其放入@ApiProperty()DTO 以及 中,@ApiOperations但无法解决问题。

下面是我想在其中捕获文件内容的函数。

@Post('/punchin')
@ApiConsumes('multipart/form-data')
@ApiOperation({ summary: 'Attendance Punch In' })
@UseInterceptors(CrudRequestInterceptor, ClassSerializerInterceptor, FileInterceptor('file'))
@ApiImplicitFile({ name: 'file' })
async punchInAttendance( @Body() body: PunchInDto, @UploadedFile() file: Express.Multer.File ): Promise<Attendance> {
    const imageUrl = await this.s3FileUploadService.upload(file)
    console.log(body, imageUrl)
    return await this.service.punchInAttendance({
      comment: body.punchInComment,
      outletId: body.outletId,
      imgUrl: imageUrl,
    })
  }
Run Code Online (Sandbox Code Playgroud)

小智 19

对我有用的解决方案是创建一个包含我将使用的 API 引用的类,并将这些字段之一设置为File.

存储对象.dto.ts

export class StorageObjectDto {
    @ApiProperty({ required: false })
    @IsString()
    comment?: string

    @ApiProperty({ type: 'string', format: 'number', required: false })
    @IsNumber()
    outletId?: number

    @ApiProperty({ type: 'string', format: 'binary', required: true })
    file: Express.Multer.File
}
Run Code Online (Sandbox Code Playgroud)

使用NestJs 文档上建议的实现,我可以根据对象内的关联键提取文件。在这种情况下,关键是file

对象.controller.ts

@Version('1')
@Post('upload')
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@Body() data: StorageObjectDto, @UploadedFile() file: Express.Multer.File): void {
    console.log({ data, file })
}
Run Code Online (Sandbox Code Playgroud)

调用端点后,您应该在控制台日志中看到以下输出

{
  data: FileDataDto {
    comment: 'This is a test comment',
    outletID: 123
  },
  file: {
    fieldname: 'file',
    originalname: 'placeholder.png',
    encoding: '7bit',
    mimetype: 'image/png',
    buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 01 f4 00 00 01 f4 04 03 00 00 00 39 f8 c2 b9 00 00 00 1b 50 4c 54 45 cc cc cc 96 96 96 9c 9c 9c ... 1069 more bytes>,
    size: 1119
  }
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ban 5

使用,@ApiBody因为 body 会保存您的数据。

  @Post('upload')
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        comment: { type: 'string' },
        outletId: { type: 'integer' },
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @UseInterceptors(FileExtender)
  @UseInterceptors(FileInterceptor('file'))
  uploadFile2(@UploadedFile('file') file) {
    console.log(file);
  }
Run Code Online (Sandbox Code Playgroud)

截屏

我进入控制台:

{
  fieldname: 'file',
  originalname: 'dart.txt',
  encoding: '7bit',
  mimetype: 'text/plain',
  buffer: <Buffer 20 0a 69 6d  ... 401 more bytes>,
  size: 451,
  comment: 'some comment',
  outletId: 123456
}
Run Code Online (Sandbox Code Playgroud)

因为FileInterceptor删除了正文参数,我使用了FileExtender拦截器来打包commentoutletId输入文件属性。

@Injectable()
export class FileExtender implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const req = context.switchToHttp().getRequest();
    req.file['comment'] = req.body.comment;
    req.file['outletId'] = Number(req.body.outletId);
    return next.handle();
  }
}
Run Code Online (Sandbox Code Playgroud)