4. 控制器与路由配置
控制器是 NestJS 处理 HTTP 请求的核心入口。本章将深入讲解 @Controller 装饰器的使用、路由前缀与参数配置、请求方法装饰器、路由通配符以及状态码管理,帮助你构建清晰、可维护的路由体系。
4.1 @Controller 装饰器:路由的起点
@Controller() 装饰器用于定义控制器类,并为其绑定一个可选的路由前缀。路由前缀可以组织相关接口,避免路径冲突。
核心语法:
import { Controller, Get } from '@nestjs/common';
@Controller('users') // 路由前缀为 /users
export class UsersController {
@Get()
findAll() {
return '返回所有用户';
}
}
当客户端请求 GET /users 时,NestJS 会自动将请求路由到 UsersController 的 findAll() 方法。
4.2 路由前缀与参数
路由前缀支持静态字符串和动态参数。动态参数使用 : 符号定义,并通过 @Param() 装饰器获取。
| 路由前缀 | 示例路径 | 匹配说明 |
|---|---|---|
@Controller('users') |
/users |
静态前缀,精确匹配 |
@Controller('users/:id') |
/users/123 |
动态参数,:id 可获取 |
@Controller('api/v1/users') |
/api/v1/users |
多级静态前缀 |
@Controller() |
/ |
无前缀,根路径 |
最佳实践: 建议为每个模块设置统一的路由前缀,例如
@Controller('users'),这样所有用户相关接口都集中在 /users 下,便于维护和版本管理。
4.3 请求方法装饰器
NestJS 提供了与 HTTP 方法对应的装饰器,用于将控制器方法绑定到特定的 HTTP 请求方法。
| 装饰器 | HTTP 方法 | 典型用途 |
|---|---|---|
@Get() |
GET | 查询资源 |
@Post() |
POST | 创建资源 |
@Put() |
PUT | 全量更新资源 |
@Patch() |
PATCH | 部分更新资源 |
@Delete() |
DELETE | 删除资源 |
@Options() |
OPTIONS | 预检请求 |
@Head() |
HEAD | 获取响应头 |
@All() |
所有方法 | 处理任意 HTTP 方法 |
完整示例:
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll() { /* 查询所有用户 */ }
@Get(':id')
findOne(@Param('id') id: string) { /* 查询单个用户 */ }
@Post()
create(@Body() createUserDto: any) { /* 创建用户 */ }
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: any) { /* 更新用户 */ }
@Delete(':id')
remove(@Param('id') id: string) { /* 删除用户 */ }
}
4.4 路由通配符与状态码
4.4.1 路由通配符
NestJS 支持在路由路径中使用通配符,用于匹配多个路径模式。常用的通配符包括 * 和 ?。
| 通配符 | 示例 | 匹配路径 |
|---|---|---|
* |
@Get('ab*cd') |
abXcd、ab123cd 等 |
? |
@Get('ab?cd') |
abXcd(仅一个字符) |
+ |
@Get('ab+cd') |
abXcd、abXXcd 等 |
( ) |
@Get('ab(cd)?e') |
abe 或 abcde |
注意: 通配符路由的匹配顺序很重要。NestJS 按照路由定义的顺序进行匹配,更具体的路由应放在通配符路由之前,避免被通配符提前拦截。
4.4.2 状态码管理
默认情况下,NestJS 会根据 HTTP 方法自动设置状态码(GET 返回 200,POST 返回 201)。你可以使用 @HttpCode() 装饰器自定义状态码。
自定义状态码示例:
import { Controller, Post, HttpCode } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Post()
@HttpCode(200) // 覆盖默认的 201 状态码
create() {
return '用户创建成功,但返回 200';
}
}
除了 @HttpCode(),你还可以使用 @Res() 装饰器直接操作响应对象,手动设置状态码和响应头。
性能提示: 尽量使用
@HttpCode() 而非 @Res(),因为 NestJS 的响应拦截器在 @Res() 模式下会失效,导致无法统一处理响应格式和日志。
4.5 控制器路由架构图
下图展示了 NestJS 控制器路由的完整处理流程,从请求进入、路由匹配到方法执行和响应返回。
4.6 控制器配置最佳实践
- 统一前缀:为每个模块设置清晰的路由前缀,如
@Controller('users'),避免路径混乱。 - 方法命名规范:使用
findAll、findOne、create、update、remove等语义化命名。 - 状态码显式声明:对于非默认状态码,使用
@HttpCode()显式声明,提高代码可读性。 - 通配符谨慎使用:通配符路由应放在具体路由之后,避免意外拦截。
- 避免使用 @Res():除非需要精细控制响应,否则优先使用 NestJS 的装饰器方式。
完整控制器示例:
import { Controller, Get, Post, Param, Body, HttpCode, HttpStatus } from '@nestjs/common';
@Controller('api/v1/users')
export class UsersController {
@Get()
findAll() {
return { data: [] };
}
@Get(':id')
findOne(@Param('id') id: string) {
return { id, name: 'John' };
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: any) {
return { id: 1, ...createUserDto };
}
}
通过合理配置控制器与路由,你可以构建出结构清晰、易于维护的 API 接口层,为后续的性能优化和功能扩展打下坚实基础。