控制器与路由
控制器负责处理传入的请求并向客户端返回响应。通过装饰器将类和方法与特定路由绑定,NestJS 提供了丰富且直观的 API 来定义路由、获取请求参数和构造响应。
一、路由定义
1. @Controller() 与路由前缀
@Controller() 装饰器用于定义控制器类,可接受一个路径前缀,从而将一组相关路由聚合在一个路径下。
import { Controller, Get } from "@nestjs/common";
@Controller("users")
export class UsersController {
@Get()
findAll() {
return "This returns all users";
}
@Get("profile")
getProfile() {
return "User profile";
}
}
- 请求
GET /users会调用findAll()。 - 请求
GET /users/profile会调用getProfile()。
2. HTTP 方法装饰器
NestJS 为每个标准 HTTP 方法提供了对应的装饰器:
| 装饰器 | HTTP 方法 | 描述 |
|---|---|---|
@Get() | GET | 获取资源 |
@Post() | POST | 创建资源 |
@Put() | PUT | 全量更新资源 |
@Patch() | PATCH | 部分更新资源 |
@Delete() | DELETE | 删除资源 |
@Options() | OPTIONS | 预检请求 |
@Head() | HEAD | 仅请求响应头 |
每个方法装饰器可以接受一个字符串参数作为路由路径(相对控制器前缀)。
@Post('create')
createUser() { ... }
3. 路由参数通配符与 Restful 风格
- 动态参数(路由参数):使用冒号
:声明,后接参数名,通过@Param()获取。
@Get(':id')
findOne(@Param('id') id: string) { ... }
- 通配符:可以使用
*匹配任意路径(仅支持末尾通配符)。
@Get('files/*')
handleWildcard() { ... }
- Restful 风格:NestJS 天然支持设计符合 REST 规范的路由,通常配合
@Get(':id')、@Post()、@Put(':id')、@Delete(':id')。
二、请求对象处理
NestJS 提供了多种装饰器来获取请求中的信息,大部分基于 Express 或 Fastify 的原生请求对象,但通过装饰器简化了访问方式。
| 装饰器 | 描述 | 示例 |
|---|---|---|
@Req() / @Request() | 获取原生请求对象 | @Req() request: Request |
@Res() / @Response() | 获取原生响应对象 | @Res() response: Response |
@Body() | 获取请求体,可选参数名 | @Body() body: CreateUserDto |
@Query() | 获取查询参数(Query String) | @Query('page') page: string |
@Param() | 获取路由参数 | @Param('id') id: string |
@Headers() | 获取请求头 | @Headers('authorization') auth: string |
@Ip() | 获取客户端 IP 地址 | @Ip() clientIp: string |
@Session() | 获取会话对象(需配置 session 中间件) | @Session() session: Record<string, any> |
注意:
- 若使用
@Res()并手动调用res.send(),则框架不会再自动处理返回值。此时需要自己发送完整响应。 - 为了同时获取原生请求和部分装饰器(如
@Body),可以注入@Req()而不使用@Res(),让框架继续自动序列化返回值。
示例:综合使用
@Post()
create(
@Body() createUserDto: CreateUserDto,
@Query('token') token: string,
@Headers('user-agent') userAgent: string,
) {
console.log(token, userAgent);
return this.usersService.create(createUserDto);
}
三、响应处理
1. 自动序列化
控制器方法返回的值如果是对象或数组,NestJS 会自动将之 JSON 序列化并设置 Content-Type: application/json。返回字符串或数字则会原样输出(作为纯文本)。
@Get()
findAll() {
return [{ id: 1, name: 'John' }]; // 自动转为 JSON
}
2. 状态码修饰
默认状态下,POST 请求返回 201 Created,其他请求返回 200 OK。可以通过 @HttpCode() 修改状态码。
@Post()
@HttpCode(204)
create() {
// 返回 204 No Content
}
3. 自定义响应头
使用 @Header() 添加自定义响应头(可同时使用多个)。
@Get()
@Header('Cache-Control', 'no-cache')
findAll() {
return 'data';
}
4. 重定向
@Redirect() 装饰器可以指定重定向的 URL 和状态码(默认 302)。也可以通过函数返回值动态重定向。
@Get('docs')
@Redirect('https://docs.example.com', 301)
getDocs() {}
// 动态重定向
@Get('legacy')
findOld(@Query('version') version) {
if (version === '2') {
return { url: 'https://new-site.com/v2', statusCode: 301 };
}
return { url: 'https://new-site.com', statusCode: 302 };
}
5. 完全控制响应流(使用 @Res())
当需要完全控制响应(例如文件下载、流式响应、设置复杂 cookie 等)时,可以注入 @Res() 对象。
import { Response } from 'express';
@Get('file')
downloadFile(@Res() res: Response) {
const file = createReadStream('file.pdf');
res.setHeader('Content-Type', 'application/pdf');
file.pipe(res);
}
注意:一旦使用 @Res() 并手动发送响应,NestJS 将中断该请求的处理链(不会执行拦截器中的 map 等操作)。如果仍希望让框架处理响应(例如只想要修改部分响应头),可以注入 @Res({ passthrough: true })。在 Nest 9+ 中支持该选项。
@Get()
find(@Res({ passthrough: true }) res: Response) {
res.setHeader('X-Custom', 'Value');
return { data: 'hello' }; // 仍然由框架自动序列化
}
四、最佳实践
- 避免混合使用
@Res()和自动返回:除非使用{ passthrough: true },否则选择其中一种方式。 - 使用 DTO 配合
@Body():通过class-validator进行数据验证。 - 路由参数装饰器顺序:不影响功能,但通常按
@Param()、@Query()、@Body()排列。 - 全局前缀:可以在
app.setGlobalPrefix('api')设置全局路由前缀,与控制器前缀叠加。
总结表
| 场景 | 使用的装饰器/工具 |
|---|---|
| 定义路径前缀 | @Controller('prefix') |
| 定义方法及子路径 | @Get('subpath')、@Post() 等 |
| 获取请求体 | @Body() |
| 获取查询参数 | @Query('name') |
| 获取路由参数 | @Param('id') |
| 获取请求头 | @Headers('key') |
| 获取客户端 IP | @Ip() |
| 获取原生请求对象 | @Req() |
| 获取原生响应对象(完全控制) | @Res() |
| 修改状态码 | @HttpCode() |
| 添加响应头 | @Header() |
| 重定向 | @Redirect() 或返回 { url, statusCode } |
| 流式/文件响应 | @Res() 手动 pipe |
通过合理使用这些装饰器,可以快速构建规范的 RESTful API,同时保持代码简洁和类型安全。
参考文献
以下链接在编写时均可正常访问:
| 资料 | 说明 |
|---|---|
| NestJS 文档 | 官方 |
| Controllers | 本章主题 |
| Request lifecycle | 执行顺序 |
相关文章
认证与授权
认证(Authentication):确认「你是谁」(如 JWT、Session)。 - 授权(Authorization):确认「你能做什么」(如 RBAC、策略检查)。
缓存
@nestjs/cache-manager 统一缓存 API,存储实现可插拔。
提供者与服务
Service 是最常见的 Provider,封装业务逻辑。见 module。
守卫 (Guards) 与授权
守卫决定是否放行请求,常用于认证与授权。见 auth。
配置管理(Config 模块)
@nestjs/config 加载 .env 并提供 ConfigService。见 工程化 env。
数据库集成(以 TypeORM 为例)
Nest 通过 @nestjs/typeorm 等包集成 ORM;生产环境用 migration,慎用 synchronize。亦可选用 Prisma、MikroORM 等(见 官方 Database)。
Series
new
5 / 19