NestJS 入门

30 阅读4分钟

官网:nestjs.com/

中文文档:www.nestjs.com.cn/

NestJS 是基于 Node.js 和 TypeScript 的渐进式后端框架,它的核心设计理念是借鉴了 Angular 的模块化思想,解决了 Express/Koa 等框架过于灵活导致的代码结构混乱问题。

image.png

image.png

image.png

安装 NestJS CLI

npm i -g @nestjs/cli

或者

pnpm i -g @nestjs/cli

验证

nest --version

image.png

创建项目

进入到本地存放项目的目录,执行(例如项目名称 demo-project)

nest new demo-project

选择包管理器,我是用的是 pnpm

image.png

创建成功

image.png

目录解析

carrierxia-admin-server/
├── node_modules/              # 项目依赖包(npm/pnpm 安装后自动生成)
├── src/                       # 源代码目录
│   ├── main.ts               # 应用入口文件,启动 NestJS 应用
│   ├── app.module.ts         # 根模块,定义应用结构
│   ├── app.controller.ts     # 根控制器,处理 HTTP 请求
│   ├── app.service.ts        # 根服务,业务逻辑层
│   └── app.controller.spec.ts # 控制器单元测试文件
├── test/                      # 测试目录
│   ├── app.e2e-spec.ts       # 端到端测试文件
│   └── jest-e2e.json         # E2E 测试配置文件
├── dist/                      # TypeScript 编译输出目录(构建后生成)
├── coverage/                  # 测试覆盖率报告目录(运行测试后生成)
├── .gitignore                 # Git 忽略文件配置
├── eslint.config.mjs          # ESLint 代码检查配置
├── nest-cli.json              # NestJS CLI 配置文件
├── package.json               # 项目配置和依赖管理
├── pnpm-lock.yaml             # pnpm 依赖锁定文件
├── README.md                  # 项目说明文档
├── tsconfig.build.json        # TypeScript 构建配置
└── tsconfig.json              # TypeScript 编译配置

启动项目

pnpm run start:dev

image.png

测试接口

在浏览器输入:http://localhost:3000/ 查看到 Hello World!

image.png

或者在终端使用 curl 命令

image.png

核心功能

模块化架构(Modular Architecture)

这是 NestJS 最核心的设计理念,强制你按模块组织代码,让项目结构清晰、可维护。应用的最小组织单元是 Module,每个模块封装一组相关的控制器、服务、提供者等。

作用:避免代码混乱,实现功能解耦,结构清晰,便于团队协作和后期维护。

// user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';

@Module({
  controllers: [UserController], // 注册控制器
  providers: [UserService],      // 注册服务/提供者
  exports: [UserService]         // 导出供其他模块使用
})
export class UserModule {}

依赖注入(Dependency Injection, DI)

NestJS 内置了完整的依赖注入系统,这是实现代码解耦和可测试性的核心。不需要手动创建类的实例,框架会自动管理依赖的创建和注入,降低组件间的耦合度。

作用:代码更加解耦,更方便测试。

// user.service.ts
import { Injectable } from '@nestjs/common';

@Injectable() // 标记为可注入的提供者
export class UserService {
  findAll() {
    return [{ id: 1, name: '张三' }];
  }
}

// user.controller.ts
import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  // 自动注入 UserService 实例
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll() {
    return this.userService.findAll(); // 调用服务方法
  }
}

控制器与路由(Controllers & Routing)

NestJS 提供了声明式的路由方式,替代了 Express/Koa 手动编写路由的方式。通过装饰器(@Controller@Get@Post@Param 等)定义路由规则,自动解析请求参数。

作用:路由规则清晰直观,参数解析自动化,减少重复代码。

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

@Controller('users') // 基础路由:/users
export class UserController {
  @Get() // GET /users
  findAll() {
    return '所有用户列表';
  }

  @Get(':id') // GET /users/1
  findOne(@Param('id') id: string) {
    return `获取 ID 为 ${id} 的用户`;
  }

  @Post() // POST /users
  create(@Body() createUserDto: any) {
    return `创建用户:${JSON.stringify(createUserDto)}`;
  }
}

中间件(Middleware)

兼容 Express/Koa 中间件,同时提供 Nest 风格的中间件实现方式。在请求到达控制器之前执行,可用于日志记录、身份验证、请求解析等。

作用:处理请求和响应

// logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next(); // 传递给下一个中间件/控制器
  }
}

// 在模块中注册
import { Module, MiddlewareConsumer } from '@nestjs/common';
@Module({})
export class AppModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('users'); // 只为 /users 路由应用中间件
  }
}

拦截器(Interceptors)

用于在请求处理前后执行逻辑,比如统一响应格式、异常处理、数据转换、缓存等。可以拦截请求和响应,修改返回结果,或捕获控制器方法的执行过程。

作用:在请求前后处理数据

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map(data => ({
        code: 200,
        message: 'success',
        data: data
      }))
    );
  }
}

// 全局注册(main.ts)
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { TransformInterceptor } from './transform.interceptor';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalInterceptors(new TransformInterceptor()); // 全局应用
  await app.listen(3000);
}
bootstrap();

过滤器(Filters)

专门用于处理异常,替代 try/catch,实现全局或局部的异常统一处理。捕获控制器 / 服务中抛出的异常,返回标准化的错误响应。

import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException) // 捕获 HttpException 及其子类
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      message: exception.getResponse(),
    });
  }
}

// 全局注册(main.ts)
app.useGlobalFilters(new HttpExceptionFilter());

 管道(Pipes)

用于数据验证和转换,比如校验请求参数格式、类型转换等。Nest 内置了多种管道(如 ValidationPipeParseIntPipe),也可自定义。

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

@Controller('users')
export class UserController {
  @Get(':id')
  // 自动将 id 转为数字,若转换失败则抛出 400 异常
  findOne(@Param('id', ParseIntPipe) id: number) {
    return `获取 ID 为 ${id} 的用户`;
  }
}

// 全局启用参数验证(main.ts)
import { ValidationPipe } from '@nestjs/common';
app.useGlobalPipes(new ValidationPipe({
  whitelist: true, // 过滤掉 DTO 中未定义的属性
  forbidNonWhitelisted: true, // 存在未定义属性时抛出异常
  transform: true, // 自动将请求数据转换为 DTO 实例
}));

守卫(Guards)

用于权限控制,决定一个请求是否能被控制器处理(比如登录验证、角色权限)。基于执行上下文判断请求是否合法,返回布尔值控制请求是否继续。

作用:实现认证和授权

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    // 模拟验证 token
    return !!request.headers.authorization;
  }
}

// 控制器级别使用
import { UseGuards } from '@nestjs/common';
@Controller('users')
@UseGuards(AuthGuard) // 该控制器下所有路由都需要验证
export class UserController {}

// 路由级别使用
@Get('profile')
@UseGuards(AuthGuard) // 仅该路由需要验证
getProfile() {
  return '用户个人信息';
}

装饰器驱动开发

整个框架基于 TypeScript 装饰器实现,所有核心功能(路由、依赖注入、中间件等)都通过装饰器声明,语法简洁且语义化。

作用:简化代码,提高可读性