目录Controller 接收参数的 5 种方式DTO 是什么DTO 为什么必须用 ClassDTO 完整实战示例快速检查清单一、Controller 接收参数的 5 种方式1. 路径参数user/:id// 单个参数Get(user/:id)findOne(Param(id)id:string){return用户ID:${id};}// 多个参数Get(user/:id/:role)findOne(Param()params:any){returnparams;// { id: 1, role: admin }}2. 查询参数user?age12nameTom// 单个参数Get(user)findAll(Query(age)age:number){return年龄:${age};}// 全部参数Get(user)findAll(Query()query:any){returnquery;// { age: 12, name: Tom }}3. 请求体JSON / Form 表单Post(user)create(Body()body:any){returnbody;// 自动解析 JSON 和 form-urlencoded}// 支持的文件类型// ✅ application/json// ✅ application/x-www-form-urlencoded// ✅ multipart/form-data需配合 FileInterceptor4. 请求头Get(info)getInfo(Headers(authorization)token:string){returnToken:${token};}5. 原生请求对象Get(test)test(Req()request:Request){returnrequest.params;// 或 request.query, request.body}二、DTO 是什么DTOData Transfer Object定义请求数据结构、类型和验证规则的对象。核心作用作用说明类型安全TypeScript 自动检查字段类型数据验证配合class-validator自动校验代码提示IDE 自动补全字段名文档生成Swagger/OpenAPI 自动生成 API 文档基础示例// create-user.dto.tsimport{IsString,IsInt,Min,Max,IsOptional}fromclass-validator;exportclassCreateUserDto{IsString()name:string;IsInt()Min(1)Max(150)age:number;IsOptional()IsString()email?:string;}三、DTO 为什么必须用 ClassInterface vs Class 对比特性InterfaceClass (DTO)编译后是否存在❌ 被删除✅ 保留支持装饰器❌ 不支持✅ 支持数据验证❌ 不能✅ 可以默认值❌ 不能✅ 可以Swagger 文档❌ 部分支持✅ 完全支持适用场景纯类型定义请求验证、响应序列化为什么 Interface 不行// ❌ Interface —— 验证不生效exportinterfaceCreateUserDto{IsString()// 装饰器被忽略name:string;}// ✅ Class —— 验证生效exportclassCreateUserDto{IsString()// 正常运行name:string;}核心原因Interface 是 TypeScript 特性编译成 JS 后消失NestJS 的ValidationPipe依赖运行时元数据reflect-metadata装饰器只能用在 Class 上实际项目分工// ✅ 请求体 —— 用 ClassexportclassCreateUserDto{IsString()name:string;}// ✅ 响应数据 —— 用 Interface纯类型exportinterfaceUserResponse{id:number;name:string;createdAt:Date;}四、DTO 完整实战示例步骤 1安装依赖npminstallclass-validator class-transformer步骤 2启用全局验证main.tsimport{ValidationPipe}fromnestjs/common;asyncfunctionbootstrap(){constappawaitNestFactory.create(AppModule);app.useGlobalPipes(newValidationPipe());awaitapp.listen(3000);}bootstrap();步骤 3创建 DTO// dto/create-user.dto.tsimport{IsString,IsInt,Min,Max,IsOptional,IsEmail}fromclass-validator;import{ApiProperty}fromnestjs/swagger;exportclassCreateUserDto{ApiProperty({example:张三})IsString()name:string;ApiProperty({example:25})IsInt()Min(1)Max(150)age:number;ApiProperty({example:zhangsanexample.com,required:false})IsOptional()IsEmail()email?:string;}// dto/query-user.dto.tsGET 请求也用 DTOimport{IsOptional,IsInt,Min}fromclass-validator;exportclassQueryUserDto{IsOptional()IsInt()Min(1)page?:number;IsOptional()IsString()name?:string;}步骤 4在 Controller 中使用Controller(users)exportclassUserController{// POST —— 使用 Body DTOPost()create(Body()createUserDto:CreateUserDto){// 自动验证通过类型安全return创建用户:${createUserDto.name};}// GET —— 使用 Query DTOGet()findAll(Query()query:QueryUserDto){return查询参数:${JSON.stringify(query)};}// GET —— 路径参数简单场景不用 DTOGet(:id)findOne(Param(id)id:string){return用户ID:${id};}}步骤 5验证效果# ✅ 请求成功POST /users{name:张三,age:25}# 返回: 创建用户: 张三# ❌ 验证失败自动返回 400POST /users{name:张三,age:200}# age 超过 150# 返回: 400 Bad Request五、快速检查清单✅ 什么时候用 DTO场景是否使用 DTO推荐方式POST/PUT/PATCH 请求体✅ 强烈推荐ClassGET 查询参数多个✅ 推荐ClassGET 路径参数少量可选直接用Param()响应数据类型✅ 推荐Interface不验证请求头❌ 不常用Headers()直接取✅ 记住这 3 条规则接收请求数据优先用 DTOClassDTO 必须用 Class不能用 Interface返回响应数据可以用 Interface纯类型✅ 常用验证装饰器IsString()// 字符串IsInt()// 整数IsNumber()// 数字含浮点IsBoolean()// 布尔值IsEmail()// 邮箱格式IsUrl()// URL 格式IsOptional()// 可选字段Min(1)// 最小值Max(150)// 最大值Length(1,10)// 字符串长度IsNotEmpty()// 非空 核心总结一句话记住请求数据用 Class DTO带验证响应类型用 Interface纯类型。GET 也能用 DTO不只是 POST