NestJS管道(Pipe) #
什么是管道? #
管道是用@Injectable()装饰器装饰的类,它实现了PipeTransform接口。管道有两个主要用途:
- 数据转换:将输入数据转换为所需格式
- 数据验证:验证输入数据,如果有效则传递,否则抛出异常
内置管道 #
NestJS提供了以下内置管道:
| 管道 | 说明 |
|---|---|
ValidationPipe |
数据验证 |
ParseIntPipe |
转换为整数 |
ParseFloatPipe |
转换为浮点数 |
ParseBoolPipe |
转换为布尔值 |
ParseArrayPipe |
转换为数组 |
ParseUUIDPipe |
验证UUID |
ParseEnumPipe |
验证枚举值 |
DefaultValuePipe |
设置默认值 |
使用内置管道 #
ParseIntPipe #
typescript
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return `User ID: ${id}, Type: ${typeof id}`;
}
}
ParseUUIDPipe #
typescript
import { Controller, Get, Param, ParseUUIDPipe } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return `User UUID: ${id}`;
}
}
ParseArrayPipe #
typescript
import { Controller, Get, Query, ParseArrayPipe } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findByIds(
@Query('ids', ParseArrayPipe) ids: number[],
) {
return ids;
}
}
DefaultValuePipe #
typescript
import { Controller, Get, Query, DefaultValuePipe } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
@Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
) {
return { page, limit };
}
}
可选管道 #
typescript
@Get(':id')
findOne(
@Param('id', new ParseIntPipe({ optional: true })) id?: number,
) {
return id;
}
ValidationPipe #
安装依赖 #
bash
npm install class-validator class-transformer
配置全局验证 #
typescript
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
);
await app.listen(3000);
}
验证选项 #
| 选项 | 说明 |
|---|---|
whitelist |
过滤未定义的属性 |
forbidNonWhitelisted |
拒绝未定义的属性 |
transform |
自动类型转换 |
disableErrorMessages |
禁用错误信息 |
validationError.target |
是否包含目标对象 |
validationError.value |
是否包含错误值 |
使用DTO验证 #
typescript
import {
IsString,
IsEmail,
IsInt,
Min,
Max,
IsOptional,
IsNotEmpty,
MinLength,
MaxLength,
IsDateString,
IsEnum,
} from 'class-validator';
export class CreateUserDto {
@IsString()
@IsNotEmpty()
@MinLength(2)
@MaxLength(50)
name: string;
@IsEmail()
email: string;
@IsInt()
@Min(0)
@Max(150)
age: number;
@IsOptional()
@IsString()
bio?: string;
@IsEnum(['male', 'female', 'other'])
gender: string;
@IsDateString()
birthday: string;
}
控制器中使用 #
typescript
import { Controller, Post, Body } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('users')
export class UsersController {
@Post()
create(@Body() createUserDto: CreateUserDto) {
return createUserDto;
}
}
嵌套对象验证 #
typescript
import { ValidateNested, IsString } from 'class-validator';
import { Type } from 'class-transformer';
class AddressDto {
@IsString()
street: string;
@IsString()
city: string;
}
export class CreateUserDto {
@IsString()
name: string;
@ValidateNested()
@Type(() => AddressDto)
address: AddressDto;
}
数组验证 #
typescript
import { IsArray, ValidateNested, IsString } from 'class-validator';
import { Type } from 'class-transformer';
class TagDto {
@IsString()
name: string;
}
export class CreatePostDto {
@IsString()
title: string;
@IsArray()
@ValidateNested({ each: true })
@Type(() => TagDto)
tags: TagDto[];
}
自定义管道 #
创建自定义管道 #
typescript
import {
PipeTransform,
Injectable,
ArgumentMetadata,
BadRequestException,
} from '@nestjs/common';
@Injectable()
export class ParseIntPipe implements PipeTransform<string, number> {
transform(value: string, metadata: ArgumentMetadata): number {
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException('Validation failed');
}
return val;
}
}
对象验证管道 #
typescript
import {
PipeTransform,
Injectable,
ArgumentMetadata,
BadRequestException,
} from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';
@Injectable()
export class CustomValidationPipe implements PipeTransform<any> {
async transform(value: any, { metatype }: ArgumentMetadata) {
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToInstance(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
const messages = errors.map(error => ({
property: error.property,
constraints: error.constraints,
}));
throw new BadRequestException({
message: 'Validation failed',
errors: messages,
});
}
return value;
}
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
数据转换管道 #
typescript
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
@Injectable()
export class TrimPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
if (typeof value === 'string') {
return value.trim();
}
if (typeof value === 'object' && value !== null) {
return this.trimObject(value);
}
return value;
}
private trimObject(obj: any): any {
const result = {};
for (const key in obj) {
if (typeof obj[key] === 'string') {
result[key] = obj[key].trim();
} else if (typeof obj[key] === 'object') {
result[key] = this.trimObject(obj[key]);
} else {
result[key] = obj[key];
}
}
return result;
}
}
管道应用范围 #
参数级别 #
typescript
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {}
方法级别 #
typescript
@Post()
@UsePipes(ValidationPipe)
create(@Body() createUserDto: CreateUserDto) {}
控制器级别 #
typescript
@Controller('users')
@UsePipes(ValidationPipe)
export class UsersController {}
全局级别 #
typescript
app.useGlobalPipes(new ValidationPipe());
管道执行顺序 #
text
请求 → 中间件 → 守卫 → 拦截器(前) → 管道 → 控制器
管道最佳实践 #
1. 使用DTO定义验证规则 #
typescript
export class CreateUserDto {
@IsString()
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
}
2. 分离创建和更新DTO #
typescript
export class CreateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
@IsString()
password: string;
}
export class UpdateUserDto extends PartialType(CreateUserDto) {
// 所有字段可选
}
3. 使用自定义错误消息 #
typescript
import { IsString, IsEmail, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString({ message: 'Name must be a string' })
@MinLength(2, { message: 'Name must be at least 2 characters' })
name: string;
@IsEmail({}, { message: 'Invalid email format' })
email: string;
}
4. 组合多个管道 #
typescript
@Get()
findAll(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
) {}
总结 #
本章学习了NestJS管道:
- 管道的概念和用途
- 内置管道的使用
- ValidationPipe配置
- 自定义管道创建
- 管道应用范围
接下来,让我们学习 守卫(Guard)。
最后更新:2026-03-28