NestJS控制器 (Controllers)
学习目标
- 理解控制器在NestJS中的作用和地位
- 掌握路由定义和HTTP方法的使用
- 学会处理各种类型的请求参数
- 能够创建基本的API端点
核心知识点
1. 控制器概念
控制器是NestJS应用的核心组件之一,负责处理传入的HTTP请求并返回响应。它们的主要职责是:
- 接收客户端请求
- 处理请求数据
- 调用相应的服务进行业务逻辑处理
- 返回处理结果给客户端
在NestJS中,控制器通过装饰器(decorators)来定义路由和HTTP方法。
2. 基本控制器创建
创建一个基本控制器的步骤:
- 使用
@Controller()装饰器标记一个类 - 在类中定义处理不同HTTP请求的方法
- 使用HTTP方法装饰器(如
@Get()、@Post()等)标记这些方法
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll() {
return 'This action returns all cats';
}
}3. 路由定义
基本路由
控制器的基本路由由@Controller()装饰器指定:
@Controller('users') // 基础路由为 /users
export class UsersController {
// ...
}方法级路由
方法级路由由HTTP方法装饰器指定,可以是相对于控制器基础路由的路径:
@Controller('users')
export class UsersController {
@Get() // 完整路由: /users
findAll() { /* ... */ }
@Get('profile') // 完整路由: /users/profile
getProfile() { /* ... */ }
}4. HTTP方法
NestJS提供了多种HTTP方法装饰器:
@Get()- 处理GET请求@Post()- 处理POST请求@Put()- 处理PUT请求@Delete()- 处理DELETE请求@Patch()- 处理PATCH请求@Options()- 处理OPTIONS请求@Head()- 处理HEAD请求@All()- 处理所有HTTP方法的请求
5. 请求参数处理
路由参数
使用@Param()装饰器获取路由参数:
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a user with id: ${id}`;
}
}查询参数
使用@Query()装饰器获取查询参数:
@Controller('users')
export class UsersController {
@Get()
findAll(@Query('limit') limit: number, @Query('offset') offset: number) {
return `This action returns users with limit: ${limit} and offset: ${offset}`;
}
}请求体
使用@Body()装饰器获取请求体:
@Controller('users')
export class UsersController {
@Post()
create(@Body() user: CreateUserDto) {
return `This action creates a user: ${user.name}`;
}
}请求头
使用@Headers()装饰器获取请求头:
@Controller('users')
export class UsersController {
@Get()
findAll(@Headers('Authorization') authorization: string) {
return `Authorization header: ${authorization}`;
}
}Cookie
使用@Cookie()装饰器获取Cookie:
@Controller('users')
export class UsersController {
@Get()
findAll(@Cookie('name') name: string) {
return `Cookie name: ${name}`;
}
}6. 响应处理
基本响应
控制器方法可以直接返回各种类型的值,NestJS会自动处理响应:
@Get()
findAll() {
return ['cat1', 'cat2', 'cat3']; // 会自动序列化为JSON
}状态码
使用@HttpCode()装饰器设置响应状态码:
@Post()
@HttpCode(201)
create() {
return 'This action creates a cat';
}响应头
使用@Header()装饰器设置响应头:
@Post()
@Header('Cache-Control', 'none')
create() {
return 'This action creates a cat';
}重定向
使用@Redirect()装饰器设置重定向:
@Get()
@Redirect('https://nestjs.com', 301)
redirect() {
// 可选的重定向逻辑
}7. 路由通配符
NestJS支持路由通配符:
@Controller('files')
export class FilesController {
@Get('ab*cd')
findAll() {
return 'This route uses a wildcard';
}
}8. 异步控制器方法
控制器方法可以是异步的,返回Promise或Observable:
@Get()
async findAll() {
return await this.catsService.findAll();
}
@Get()
findAll(): Observable<any[]> {
return this.catsService.findAll();
}实践案例分析
案例:创建一个用户管理API
需求分析
我们需要创建一个简单的用户管理API,支持以下功能:
- 获取所有用户
- 获取单个用户
- 创建新用户
- 更新用户信息
- 删除用户
实现步骤
- 创建用户控制器
- 定义路由和HTTP方法
- 实现请求参数处理
- 添加响应处理
代码实现
import {
Controller,
Get,
Post,
Put,
Delete,
Param,
Body,
Query,
HttpCode,
HttpStatus,
} from '@nestjs/common';
// 简单的DTO类
class CreateUserDto {
name: string;
email: string;
}
class UpdateUserDto {
name?: string;
email?: string;
}
@Controller('users')
export class UsersController {
// 模拟用户数据
private users = [
{ id: '1', name: '张三', email: 'zhangsan@example.com' },
{ id: '2', name: '李四', email: 'lisi@example.com' },
];
@Get()
findAll(@Query('limit') limit?: number) {
if (limit) {
return this.users.slice(0, limit);
}
return this.users;
}
@Get(':id')
findOne(@Param('id') id: string) {
const user = this.users.find(u => u.id === id);
if (!user) {
return { status: 404, message: 'User not found' };
}
return user;
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: CreateUserDto) {
const newUser = {
id: (this.users.length + 1).toString(),
...createUserDto,
};
this.users.push(newUser);
return newUser;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
const index = this.users.findIndex(u => u.id === id);
if (index === -1) {
return { status: 404, message: 'User not found' };
}
this.users[index] = {
...this.users[index],
...updateUserDto,
};
return this.users[index];
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string) {
const index = this.users.findIndex(u => u.id === id);
if (index === -1) {
return { status: 404, message: 'User not found' };
}
this.users.splice(index, 1);
return;
}
}代码解析
- 路由定义:使用
@Controller('users')定义基础路由为/users - HTTP方法:使用
@Get(),@Post(),@Put(),@Delete()装饰器定义不同的HTTP方法处理 - 参数处理:
- 使用
@Param()获取路由参数 - 使用
@Body()获取请求体 - 使用
@Query()获取查询参数
- 使用
- 响应处理:
- 使用
@HttpCode()设置响应状态码 - 直接返回数据,NestJS会自动序列化
- 使用
测试结果
| 请求方法 | 请求路径 | 描述 | 预期响应 |
|---|---|---|---|
| GET | /users | 获取所有用户 | [{"id":"1","name":"张三","email":"zhangsan@example.com"},{"id":"2","name":"李四","email":"lisi@example.com"}] |
| GET | /users?limit=1 | 获取1个用户 | [{"id":"1","name":"张三","email":"zhangsan@example.com"}] |
| GET | /users/1 | 获取ID为1的用户 | {"id":"1","name":"张三","email":"zhangsan@example.com"} |
| POST | /users | 创建新用户 | {"id":"3","name":"王五","email":"wangwu@example.com"} (状态码: 201) |
| PUT | /users/1 | 更新用户信息 | {"id":"1","name":"张三更新","email":"zhangsan@example.com"} |
| DELETE | /users/1 | 删除用户 | 空响应 (状态码: 204) |
互动思考问题
思考:控制器和服务的职责有什么不同?在实际应用中如何划分它们的边界?
讨论:在处理复杂的业务逻辑时,控制器应该直接实现业务逻辑还是调用服务层?为什么?
实践:尝试创建一个博客API,支持文章的CRUD操作,包括获取所有文章、获取单篇文章、创建文章、更新文章和删除文章。
挑战:如何处理控制器中的错误?例如,当用户请求不存在的资源时,应该返回什么状态码和错误信息?
扩展:了解NestJS的路由守卫(Guards)和拦截器(Interceptors),思考它们如何与控制器配合使用来实现更复杂的功能。
小结
本集我们学习了NestJS控制器的核心概念和使用方法,包括:
- 控制器的基本概念和作用
- 路由定义和HTTP方法的使用
- 各种类型的请求参数处理
- 响应处理和状态码设置
- 异步控制器方法的实现
通过实践案例,我们创建了一个完整的用户管理API,展示了控制器的实际应用。控制器是NestJS应用的入口点,它们接收和处理客户端请求,是构建API的基础组件。
在下一集中,我们将学习NestJS的提供者(Providers),了解NestJS的依赖注入系统,这将帮助我们更好地组织和管理应用的业务逻辑。