nestjs中body验证失败时如何阻止文件上传

问题描述 投票:0回答:3

在 Nestjs 应用程序中上传文件之前,我需要验证多部分表单。问题是,如果正文验证失败,我不希望上传文件。 这是我编写代码的方式。

// User controller method for create user with upload image
@Post()
@UseInterceptors(FileInterceptor('image'))
create(
    @Body() userInput: CreateUserDto,
    @UploadedFile(
        new ParseFilePipe({
          validators: [
             // some validator here
          ]
        })
    ) image: Express.Multer.File,
) {
    return this.userService.create({ ...userInput, image: image.path });
}

尝试了很多方法来扭转这个问题,但没有达到任何解决方案

node.js validation file-upload nestjs nest
3个回答
3
投票

拦截器在管道之前运行,因此除非您在服务中自行管理,否则无法保存文件不会发生。但是,另一个选项可能是自定义异常过滤器,它unlink

是错误的文件,这样您就不必担心上传后的问题


2
投票
这就是我创建整个过滤器的方式

import { isArray } from 'lodash'; import { ExceptionFilter, Catch, ArgumentsHost, BadRequestException, } from '@nestjs/common'; import { Request, Response } from 'express'; import * as fs from 'fs'; @Catch(BadRequestException) export class DeleteFileOnErrorFilter implements ExceptionFilter { catch(exception: BadRequestException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); const status = exception.getStatus(); const getFiles = (files: Express.Multer.File[] | unknown | undefined) => { if (!files) return []; if (isArray(files)) return files; return Object.values(files); }; const filePaths = getFiles(request.files); for (const file of filePaths) { fs.unlink(file.path, (err) => { if (err) { console.error(err); return err; } }); } response.status(status).json(exception.getResponse()); } }
    

0
投票
我建议在调用控制器后使用 multer 的内存存储和拦截器来保存文件。 这样验证将在保存文件之前运行。 如果验证失败,请求将跳过保存文件拦截器并由过滤器处理。

保存文件.interceptor.ts

import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from '@nestjs/common'; import { Observable, throwError, tap } from 'rxjs'; import { writeFile, existsSync, mkdirSync } from 'fs'; import { join } from 'path'; import { Request } from 'express'; @Injectable() export class SaveFileInterceptor implements NestInterceptor { saveFile(file: Express.Multer.File) { const fileType = file.mimetype ? file.mimetype.split('/')[0] : 'others'; const destination = join(__dirname, `../../src/public/upload/${fileType}`); if (!existsSync(destination)) { mkdirSync(destination, { recursive: true }); } writeFile( `${destination}/${file.filename}`, file.buffer, err => { if (err) { console.log(err); throwError(err); } } ) } generateFilePath(file: Express.Multer.File) { const fileType = file.mimetype ? file.mimetype.split('/')[0] : 'others'; file.path = `/upload/${fileType}/${file.filename}`; // path served as static file } generateFileName(file: Express.Multer.File) { file.filename = Date.now() + '-' + Math.round(Math.random() * 1E9); } intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const req: Request = context.switchToHttp().getRequest(); if (req.file) { this.generateFileName(req.file); this.generateFilePath(req.file); } if (req.files) { if (Array.isArray(req.files)) { req.files.forEach(file => { this.generateFileName(file); this.generateFilePath(file); }); } else { Object.values(req.files).flat().forEach(file => { this.generateFileName(file); this.generateFilePath(file); }); } } return next.handle().pipe(tap(() => { if (req.file) { this.saveFile(req.file); } if (req.files) { if (Array.isArray(req.files)) { req.files.forEach(file => this.saveFile(file)); } else { Object.values(req.files).flat().forEach(file => this.saveFile(file)); } } })); } }
控制器

import { Controller, Post, Body, UseInterceptors, UploadedFile, UploadedFiles, ParseFilePipeBuilder, HttpStatus, } from '@nestjs/common'; import { Public } from '../auth/public.decorator'; import { FileFieldsInterceptor, FileInterceptor, FilesInterceptor, } from '@nestjs/platform-express'; import { FileTypeValidator, FileSizeValidator } from 'src/common'; import { SaveFileInterceptor } from 'src/interceptors/save-file.interceptor'; import { UploadOneFileDto } from './upload.dto'; @Public() @Controller('upload') export class UploadController { @Post('/one-file') @UseInterceptors( FileInterceptor('file'), SaveFileInterceptor ) uploadOneFile( @UploadedFile( new ParseFilePipeBuilder() .addMaxSizeValidator({ maxSize: 1024 * 1024 }) .addFileTypeValidator({ fileType: /.(jpg|jpeg|png)$/ }) .build({ errorHttpStatusCode: HttpStatus.BAD_REQUEST }), ) file: Express.Multer.File, @Body() body: UploadOneFileDto ) { console.log(file); } }
    
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.