Skip to content

Nest 基础概念

Nest.js 是一个 Node.js 的后端框架,类似于 Java 的 Spring。它提供了完整的应用架构,帮助我们更好地组织代码结构。

1. 请求处理流程

Controller(控制器)

Controller 负责处理传入的请求和向客户端返回响应:

ts
@Controller("user")
export class UserController {
  @Get("list") // GET /user/list
  getUsers() {
    return ["小明", "小红"];
  }

  @Post("create") // POST /user/create
  createUser() {
    return "创建成功";
  }
}

请求参数装饰器

  1. @Params - 路径参数
ts
@Get(':userId')
getUser(@Param('userId') userId: string) {
  return userId;  // GET /user/123
}
  1. @Query - 查询参数
ts
@Get('search')
searchUsers(@Query('name') name: string, @Query('age') age: number) {
  return `查询:${name}, ${age}`;  // GET /user/search?name=小明&age=18
}
  1. @Body - 请求体
ts
@Post()
createUser(@Body() user: CreateUserDto) {
  return { success: true, data: user };  // POST /user  body: {...}
}

DTO(数据传输对象)

DTO 作为请求数据的验证层:

DTO作为数据验证层示意图
ts
export class CreateUserDto {
  @IsString()
  @IsNotEmpty()
  name: string;

  @IsEmail()
  email: string;

  @IsNumber()
  @Min(0)
  age: number;

  @IsEnum(["admin", "user"])
  role: "admin" | "user";
}

Entity(实体)

Entity 用于映射数据库表结构:

ts
// user.entity.ts
@Entity("users")
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column({ unique: true })
  email: string;

  @Column()
  age: number;

  @Column({
    type: "enum",
    enum: ["admin", "user"],
    default: "user",
  })
  role: string;

  @Column({ select: false }) // 查询时默认不返回密码字段
  password: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  // 关联关系
  @OneToMany(() => Post, (post) => post.author)
  posts: Post[];

  @ManyToMany(() => Role)
  @JoinTable()
  roles: Role[];
}

Entity 与 DTO 的区别:

  1. Entity

    • 映射数据库表结构
    • 使用 TypeORM 装饰器(@Entity, @Column 等)
    • 包含完整的数据库字段(id, 创建时间等)
    • 可以定义表关系(一对多,多对多等)
    • 通常与整个应用生命周期相关
  2. DTO

    • 用于请求数据的验证和传输
    • 使用验证装饰器(@IsString, @IsEmail 等)
    • 只包含请求需要的字段
    • 不包含敏感信息(如密码)
    • 通常与具体请求相关(CreateUserDto, UpdateUserDto)

2. 依赖注入(DI)

Service 注入

Service 封装业务逻辑,通过依赖注入的方式与 Controller 协作:

ts
@Injectable()
export class UserService {
  async createUser(user: CreateUserDto) {
    // 业务逻辑
    return { id: 1, ...user };
  }
}

@Controller("user")
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  createUser(@Body() user: CreateUserDto) {
    return this.userService.createUser(user);
  }
}

Provider 类型

ts
@Module({
  providers: [
    UserService,                      // 标准写法
    {
      provide: 'APP_SERVICE',         // useClass
      useClass: AppService
    },
    {
      provide: 'CONFIG',              // useValue
      useValue: { apiUrl: '...' }
    },
    {
      provide: 'ASYNC_SERVICE',       // useFactory
      useFactory: async () => {
        const config = await loadConfig();
        return new Service(config);
      }
    }
  ]
})

注入方式

  1. 构造器注入
ts
@Controller("user")
export class UserController {
  // 标准 Service 可以直接注入
  constructor(
    private readonly userService: UserService,
    private readonly authService: AuthService,
    // 自定义 provider 需要用 @Inject
    @Inject("CONFIG") private readonly config: AppConfig,
    @Inject("DATABASE") private readonly db: Database
  ) {}
}
  1. 属性注入
ts
@Controller("user")
export class UserController {
  @Inject(UserService)
  private readonly userService: UserService;

  @Inject("CONFIG")
  private readonly config: AppConfig;
}

3. 项目结构

标准的模块结构:

text
src/
├── user/
│   ├── dto/
│   │   └── create-user.dto.ts
│   ├── entities/
│   │   └── user.entity.ts
│   ├── user.controller.ts
│   ├── user.service.ts
│   └── user.module.ts
├── app.module.ts
└── main.ts

4. MVC 架构

controller 是处理路由,解析请求参数的。

service 是处理业务逻辑的,比如操作数据库。

dto 是封装请求参数的。

entities 是封装对应数据库表的实体的。

nest 应用跑起来后,会从 AppModule 开始解析,初始化 IoC 容器,加载所有的 service 到容器里,然后解析 controller 里的路由,接下来就可以接收请求了。

Nest MVC架构图

MVC 是一种软件架构模式,它将应用程序分为三个主要部分:

  1. Model(模型)

    • Service: 处理业务逻辑
    • Repository: 负责数据访问
    • Entity: 数据库实体定义
  2. View(视图)

    • 在 Nest 中通常是 JSON 响应
    • 也可以是模板引擎渲染的 HTML
    • 或者其他格式的响应数据
  3. Controller(控制器)

    • 处理 HTTP 请求
    • 参数验证和转换
    • 调用相应的 Service
    • 返回处理结果

这种分层架构的好处:

  • 关注点分离
  • 代码复用
  • 便于维护和测试
  • 提高代码的可读性和可维护性

5. AOP 架构

AOP切面编程示意图

Nest 提供了 5 种切面:

Nest的5种切面类型
  • Middleware: 中间件
  • Guard: 守卫
  • Interceptor: 拦截器
  • Pipe: 管道
  • Exception Filter: 异常过滤器

总结

controller:控制器,用于处理路由,解析请求参数

handler:控制器里处理路由的方法

service:实现业务逻辑的地方,比如操作数据库等

dto:data transfer object,数据传输对象,用于封装请求体里数据的对象

module:模块,包含 controller、service 等,比如用户模块、书籍模块

entity:对应数据库表的实体

ioc:Inverse of Controller,反转控制或者叫依赖注入,只要声明依赖,运行时 Nest 会自动注入依赖的实例

aop:Aspect Oriented Programming 面向切面编程,在多个请求响应流程中可以复用的逻辑,比如日志记录等,具体包含 middleware、interceotor、guard、exception filter、pipe

Crafted with care.