NestJS中ValidationGuard无法获取请求数据问题求助
NestJS中ValidationGuard与FileInterceptor共存时无法获取请求数据的问题解决
问题原因
NestJS的请求处理生命周期中,守卫(Guard)的执行时机早于拦截器(Interceptor)。FileInterceptor属于拦截器,它会在自身执行阶段解析multipart/form-data格式的请求,将文件挂载到req.file、表单数据挂载到req.body上。而ValidationGuard在拦截器执行前就会运行,此时请求数据还未被解析,自然会出现req.body为空、req.file为undefined的情况。
解决方法
方法一:用ValidationPipe替代ValidationGuard做DTO验证
官方推荐的DTO验证方式是使用ValidationPipe,它的执行时机在拦截器之后、控制器方法执行之前,此时FileInterceptor已经完成了请求数据的解析,能正常获取到body和file数据。
示例代码:
import { Controller, Post, UseInterceptors, UsePipes, Body, UploadedFile } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { ValidationPipe } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; @Controller('users') export class UsersController { @Post() @UseInterceptors(FileInterceptor('avatar')) // 先执行文件拦截器解析数据 @UsePipes(new ValidationPipe({ transform: true, whitelist: true })) // 再用管道验证DTO async createUser( @Body() createUserDto: CreateUserDto, @UploadedFile() file: Express.Multer.File, ) { // 处理业务逻辑 return { createUserDto, file }; } }
方法二:自定义守卫并手动解析请求(不推荐)
如果一定要使用守卫,可以在自定义守卫中手动调用multer的解析逻辑,但这种方式会增加代码复杂度,不如使用ValidationPipe简洁。示例代码(仅作参考):
import { Injectable, CanActivate, ExecutionContext, BadRequestException } from '@nestjs/common'; import { multer } from 'multer'; import { CreateUserDto } from './dto/create-user.dto'; import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; @Injectable() export class CustomValidationGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise<boolean> { const req = context.switchToHttp().getRequest(); // 手动用multer解析multipart/form-data await new Promise((resolve, reject) => { const upload = multer().single('avatar'); upload(req, null, (err) => { if (err) reject(new BadRequestException('文件解析失败')); else resolve(null); }); }); // 验证DTO const createUserDto = plainToInstance(CreateUserDto, req.body); const errors = await validate(createUserDto); if (errors.length > 0) { throw new BadRequestException('表单数据验证失败'); } return true; } }
注意:这种方式需要自行处理multer的配置和异常,不如官方管道省心,优先推荐方法一。
内容的提问来源于stack exchange,提问作者Aleksandr Kis
相关产品推荐
相关产品推荐

