Skip to content

控制器

什么是控制器?

想象一下,你在一家餐厅点餐:

  • 你(客户端)告诉服务员(控制器)你想要什么菜
  • 服务员把你的需求传达给厨房(服务层)
  • 厨房做好菜后,服务员把菜端给你

在 NestJS 中,控制器(Controller) 就是那个"服务员",它负责:

  1. 接收来自客户端的请求
  2. 处理请求并调用相应的业务逻辑
  3. 返回响应给客户端

基本语法

1. 创建一个简单的控制器

typescript
import { Controller, Get } from '@nestjs/common';

@Controller('cats')  // 这是控制器装饰器
export class CatsController {
  @Get()  // 这是路由装饰器
  findAll(): string {
    return '这个接口返回所有猫咪信息';
  }
}

解释:

  • @Controller('cats') 表示这个控制器处理所有以 /cats 开头的请求
  • @Get() 表示这个方法处理 GET 请求
  • 当访问 GET /cats 时,会调用 findAll() 方法

2. 不同的HTTP方法

typescript
import { Controller, Get, Post, Put, Delete } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get()
  getAllUsers() {
    return '获取所有用户';
  }

  @Post()
  createUser() {
    return '创建新用户';
  }

  @Put()
  updateUser() {
    return '更新用户信息';
  }

  @Delete()
  deleteUser() {
    return '删除用户';
  }
}

访问方式:

  • GET /usersgetAllUsers()
  • POST /userscreateUser()
  • PUT /usersupdateUser()
  • DELETE /usersdeleteUser()

路由参数

1. 路径参数

typescript
import { Controller, Get, Param } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    return `查找ID为 ${id} 的用户`;
  }

  @Get(':id/posts/:postId')
  findUserPost(
    @Param('id') userId: string,
    @Param('postId') postId: string
  ) {
    return `用户 ${userId} 的文章 ${postId}`;
  }
}

示例访问:

  • GET /users/123 → 返回 "查找ID为 123 的用户"
  • GET /users/123/posts/456 → 返回 "用户 123 的文章 456"

2. 查询参数

typescript
import { Controller, Get, Query } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Query() query: any) {
    return `搜索参数: ${JSON.stringify(query)}`;
  }

  @Get('search')
  search(
    @Query('keyword') keyword: string,
    @Query('page') page: number = 1
  ) {
    return `搜索关键词: ${keyword}, 页码: ${page}`;
  }
}

示例访问:

  • GET /products?category=electronics&price=100
  • GET /products/search?keyword=laptop&page=2

请求体处理

1. 接收POST数据

typescript
import { Controller, Post, Body } from '@nestjs/common';

// 定义数据传输对象(DTO)
export class CreateUserDto {
  name: string;
  email: string;
  age: number;
}

@Controller('users')
export class UsersController {
  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return `创建用户: ${createUserDto.name}, 邮箱: ${createUserDto.email}`;
  }

  @Post('login')
  login(@Body() loginData: { username: string; password: string }) {
    return `用户 ${loginData.username} 尝试登录`;
  }
}

2. 组合使用参数和请求体

typescript
import { Controller, Put, Param, Body } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() updateData: { name?: string; email?: string }
  ) {
    return `更新用户 ${id}: ${JSON.stringify(updateData)}`;
  }
}

更多装饰器

1. 请求头处理

typescript
import { Controller, Get, Headers } from '@nestjs/common';

@Controller('api')
export class ApiController {
  @Get('info')
  getInfo(@Headers('authorization') auth: string) {
    return `认证信息: ${auth}`;
  }
}

2. 响应对象

typescript
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';

@Controller('files')
export class FilesController {
  @Get('download')
  downloadFile(@Res() res: Response) {
    res.download('./files/example.txt');
  }
}

实际应用示例

完整的用户管理控制器

typescript
import { Controller, Get, Post, Put, Delete, Param, Body, Query } from '@nestjs/common';

// 数据传输对象
export class CreateUserDto {
  name: string;
  email: string;
  age: number;
}

export class UpdateUserDto {
  name?: string;
  email?: string;
  age?: number;
}

@Controller('users')
export class UsersController {
  // 获取所有用户(支持分页)
  @Get()
  findAll(@Query('page') page: number = 1, @Query('limit') limit: number = 10) {
    return `获取用户列表 - 第${page}页,每页${limit}条`;
  }

  // 根据ID获取用户
  @Get(':id')
  findOne(@Param('id') id: string) {
    return `获取用户 ${id} 的详细信息`;
  }

  // 创建新用户
  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return `创建用户: ${createUserDto.name}`;
  }

  // 更新用户信息
  @Put(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return `更新用户 ${id} 的信息`;
  }

  // 删除用户
  @Delete(':id')
  remove(@Param('id') id: string) {
    return `删除用户 ${id}`;
  }

  // 搜索用户
  @Get('search/:keyword')
  search(@Param('keyword') keyword: string) {
    return `搜索包含 "${keyword}" 的用户`;
  }
}

控制器的注册

创建控制器后,需要在模块中注册:

typescript
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  controllers: [UsersController],  // 在这里注册控制器
  providers: [UsersService],
})
export class UsersModule {}

命令行快速创建

NestJS 提供了命令行工具来快速创建控制器:

bash
# 创建一个名为 cats 的控制器
nest generate controller cats

# 简写形式
nest g controller cats

# 创建完整的 CRUD 控制器
nest g resource cats

常见错误和解决方案

1. 路由冲突

typescript
// ❌ 错误:会产生冲突
@Controller('users')
export class UsersController {
  @Get('active')
  getActiveUsers() { ... }

  @Get(':id')  // 这个会拦截所有GET请求,包括 /users/active
  getUser(@Param('id') id: string) { ... }
}

// ✅ 正确:具体路由放在参数路由前面
@Controller('users')
export class UsersController {
  @Get(':id')
  getUser(@Param('id') id: string) { ... }

  @Get('active')  // 这样就不会冲突了
  getActiveUsers() { ... }
}

2. 参数类型转换

typescript
@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    // id 始终是字符串,如果需要数字要手动转换
    const userId = parseInt(id, 10);
    return `用户ID: ${userId}`;
  }
}

总结

控制器是 NestJS 应用的入口点,它们:

  1. 定义路由 - 决定哪个 URL 对应哪个方法
  2. 处理请求 - 接收和解析客户端发送的数据
  3. 返回响应 - 把处理结果返回给客户端

记住这个模式:

  • @Controller() 装饰器定义控制器
  • @Get(), @Post() 等装饰器定义路由
  • @Param(), @Body(), @Query() 等装饰器获取请求数据

从简单的例子开始,逐步增加复杂度,你很快就能掌握 NestJS 控制器的使用!