首页 / NestJS 入门教程 / 请求参数处理

NestJS 入门教程

请求参数处理

本教程共 47 篇 · 第 12 篇 · 更新于 2026-08-09 · 约 10 分钟阅读

NestJS请求参数ParamQueryBodyDTO文件上传自定义装饰器

本节目标:掌握从 HTTP 请求中提取各种参数的方式,学会用 DTO 做数据验证,以及自定义参数装饰器。

参数提取装饰器一览

NestJS 提供了一组装饰器,帮你从请求的不同位置提取数据:

装饰器提取来源示例
@Param()URL 路径参数/users/:id
@Query()查询字符串?page=1&limit=10
@Body()请求体POST/PUT 的 JSON 数据
@Headers()请求头Authorization: Bearer xxx
@Cookies()Cookietoken=abc123
@Session()Session会话数据
@Ip()客户端 IP请求来源 IP

@Param() — 路径参数

从 URL 路径中提取动态值:

@Get(':id')
findOne(@Param('id') id: string) {
  return `用户 ID: ${id}`;
}

访问 GET /users/42id 的值是 '42'

多个路径参数:

@Get(':userId/posts/:postId')
getUserPost(
  @Param('userId') userId: string,
  @Param('postId') postId: string,
) {
  return `用户 ${userId} 的文章 ${postId}`;
}

一次拿全部:

@Get(':userId/posts/:postId')
getUserPost(@Param() params: { userId: string; postId: string }) {
  return params;
}

类型转换

URL 参数默认是字符串。如果需要数字类型,用 ParseIntPipe

@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
  return typeof id;  // 'number'
}

如果传的不是数字(比如 /users/abc),ParseIntPipe 会直接抛 400 错误。

@Query() — 查询参数

从 URL 查询字符串中提取数据:

@Get()
findAll(
  @Query('page') page: string,
  @Query('limit') limit: string,
) {
  return `第 ${page} 页,每页 ${limit} 条`;
}

访问 GET /users?page=1&limit=10

一次拿全部查询参数:

@Get()
findAll(@Query() query: Record<string, string>) {
  return query;
}

用 DTO 组织查询参数

查询参数多了之后,用 DTO 来组织更清晰:

import { IsOptional, IsInt, Min } from 'class-validator';
import { Type } from 'class-transformer';

export class PaginationDto {
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  page?: number = 1;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  limit?: number = 10;
}

@Get()
findAll(@Query() pagination: PaginationDto) {
  return pagination;
}
Tip

@Type(() => Number) 配合 ValidationPipetransform: true 选项,能把字符串自动转成数字。不然 ?page=1 拿到的还是字符串 '1'

@Body() — 请求体

从 POST/PUT 请求的 body 中提取数据:

@Post()
create(@Body() createUserDto: CreateUserDto) {
  return this.usersService.create(createUserDto);
}

提取单个字段:

@Post()
create(
  @Body('name') name: string,
  @Body('email') email: string,
) {
  return { name, email };
}

DTO 验证

class-validator 给 DTO 加验证规则:

npm install class-validator class-transformer
import { IsString, IsEmail, IsInt, Min, Max, IsOptional, IsNotEmpty } from 'class-validator';

export class CreateUserDto {
  @IsString()
  @IsNotEmpty()
  name: string;

  @IsEmail()
  email: string;

  @IsInt()
  @Min(0)
  @Max(150)
  age: number;

  @IsOptional()
  @IsString()
  bio?: string;
}

main.ts 里开启全局验证管道:

import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,            // 自动过滤 DTO 中未定义的属性
    forbidNonWhitelisted: true, // 有未定义属性时直接报错
    transform: true,            // 自动类型转换
  }));
  await app.listen(3000);
}
bootstrap();
Note

whitelist: true 非常实用。如果客户端传了 DTO 里没有的字段,会被自动过滤掉。防止恶意用户注入意外数据。

@Headers() — 请求头

@Get()
findAll(@Headers('authorization') auth: string) {
  return `Token: ${auth}`;
}

获取所有请求头:

@Get()
findAll(@Headers() headers: Record<string, string>) {
  return headers;
}

需要先安装 cookie-parser

npm install cookie-parser

main.ts 中配置:

import * as cookieParser from 'cookie-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(cookieParser());
  await app.listen(3000);
}
bootstrap();

然后就能用了:

@Get()
findAll(@Cookies('token') token: string) {
  return { token };
}

文件上传

单文件上传

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

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    return {
      filename: file.originalname,
      size: file.size,
      mimetype: file.mimetype,
    };
  }
}

FileInterceptor('file') 里的 'file' 是表单字段名。前端上传时,文件字段的 name 必须是 file

多文件上传

@Post('multiple')
@UseInterceptors(FilesInterceptor('files', 10))
uploadFiles(@UploadedFiles() files: Express.Multer.File[]) {
  return files.map(f => ({ name: f.originalname, size: f.size }));
}

多字段文件上传

@Post('fields')
@UseInterceptors(
  FileFieldsInterceptor([
    { name: 'avatar', maxCount: 1 },
    { name: 'documents', maxCount: 10 },
  ]),
)
uploadFiles(
  @UploadedFiles() files: {
    avatar?: Express.Multer.File[];
    documents?: Express.Multer.File[];
  },
) {
  return files;
}
Tip

文件上传默认存在内存里。生产环境建议配合 multer 的磁盘存储,或者上传到 OSS/S3。

自定义参数装饰器

如果你经常需要获取当前登录用户的信息,可以封装一个自定义装饰器:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CurrentUser = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;

    return data ? user?.[data] : user;
  },
);

使用方式:

@Get('profile')
getProfile(@CurrentUser() user: User) {
  return user;
}

@Get('email')
getEmail(@CurrentUser('email') email: string) {
  return { email };
}

@CurrentUser() 获取整个用户对象,@CurrentUser('email') 获取用户的 email 字段。

Note

自定义装饰器依赖 request.user,这通常是认证守卫(Guard)设置的。后面学守卫时会详细讲。

小结

请求参数处理是 NestJS 开发中最常用的操作。

核心装饰器:

  • @Param() — 路径参数
  • @Query() — 查询参数
  • @Body() — 请求体
  • @Headers() — 请求头
  • @Cookies() — Cookie

进阶技巧:

  • 用 DTO + class-validator 做数据验证
  • ValidationPipewhitelisttransform 选项
  • createParamDecorator 封装自定义装饰器