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 控制器路由的完整处理流程,从请求进入、路由匹配到方法执行和响应返回。

NestJS 控制器路由处理流程 NestJS 控制器路由处理流程 HTTP 请求 路由匹配 控制器方法执行 响应处理 返回 HTTP 响应 路由匹配细节 • 前缀匹配:/users • 方法匹配:GET/POST 等 • 通配符匹配:* ? + • 参数提取::id 响应处理细节 • 状态码:@HttpCode() • 响应拦截器 • 异常过滤器

4.6 控制器配置最佳实践

  1. 统一前缀:为每个模块设置清晰的路由前缀,如 @Controller('users'),避免路径混乱。
  2. 方法命名规范:使用 findAll、findOne、create、update、remove 等语义化命名。
  3. 状态码显式声明:对于非默认状态码,使用 @HttpCode() 显式声明,提高代码可读性。
  4. 通配符谨慎使用:通配符路由应放在具体路由之后,避免意外拦截。
  5. 避免使用 @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 接口层,为后续的性能优化和功能扩展打下坚实基础。