Skip to content

NestJS 企业级框架

NestJS 是基于 TypeScript 的 Node.js 框架,借鉴 Angular 的模块化架构,适合构建可维护的企业级后端。

核心架构

NestJS 架构(MVC + 依赖注入):

Request → Middleware → Guard → Interceptor → Pipe → Controller → Service → Repository

Response ← Interceptor ← ExceptionFilter ←────────────────────────────── Database

快速开始

bash
npm install -g @nestjs/cli
nest new my-api
cd my-api

# 生成资源(CRUD 模块)
nest generate resource users

模块、控制器、服务

ts
// users/users.module.ts
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { UsersController } from './users.controller'
import { UsersService } from './users.service'
import { User } from './entities/user.entity'

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],  // 允许其他模块使用
})
export class UsersModule {}

// users/users.controller.ts
import { Controller, Get, Post, Body, Param, Patch, Delete,
         ParseIntPipe, UseGuards, HttpCode, HttpStatus } from '@nestjs/common'
import { UsersService } from './users.service'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'

@Controller('users')
@UseGuards(JwtAuthGuard)  // 整个控制器需要认证
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  @HttpCode(HttpStatus.CREATED)
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto)
  }

  @Get()
  findAll() {
    return this.usersService.findAll()
  }

  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.usersService.findOne(id)
  }

  @Patch(':id')
  update(
    @Param('id', ParseIntPipe) id: number,
    @Body() updateUserDto: UpdateUserDto
  ) {
    return this.usersService.update(id, updateUserDto)
  }

  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  remove(@Param('id', ParseIntPipe) id: number) {
    return this.usersService.remove(id)
  }
}

// users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User } from './entities/user.entity'
import { CreateUserDto } from './dto/create-user.dto'

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>
  ) {}

  async create(dto: CreateUserDto): Promise<User> {
    const user = this.userRepository.create(dto)
    return this.userRepository.save(user)
  }

  async findAll(): Promise<User[]> {
    return this.userRepository.find()
  }

  async findOne(id: number): Promise<User> {
    const user = await this.userRepository.findOne({ where: { id } })
    if (!user) throw new NotFoundException(`用户 #${id} 不存在`)
    return user
  }

  async update(id: number, dto: UpdateUserDto): Promise<User> {
    const user = await this.findOne(id)
    Object.assign(user, dto)
    return this.userRepository.save(user)
  }

  async remove(id: number): Promise<void> {
    const user = await this.findOne(id)
    await this.userRepository.remove(user)
  }
}

DTO 与验证

ts
// users/dto/create-user.dto.ts
import { IsEmail, IsString, MinLength, IsEnum, IsOptional } from 'class-validator'
import { Transform } from 'class-transformer'

export class CreateUserDto {
  @IsString()
  @MinLength(2, { message: '姓名至少 2 个字符' })
  name: string

  @IsEmail({}, { message: '邮箱格式不正确' })
  @Transform(({ value }) => value.toLowerCase())
  email: string

  @IsString()
  @MinLength(8, { message: '密码至少 8 位' })
  password: string

  @IsEnum(['admin', 'user'])
  @IsOptional()
  role?: 'admin' | 'user' = 'user'
}

// 启用全局验证管道
// main.ts
import { ValidationPipe } from '@nestjs/common'

app.useGlobalPipes(new ValidationPipe({
  whitelist: true,      // 自动剥离未声明的属性
  forbidNonWhitelisted: true,  // 有未知属性时报错
  transform: true,      // 自动类型转换
  transformOptions: { enableImplicitConversion: true }
}))

JWT 认证

ts
// auth/auth.module.ts
import { JwtModule } from '@nestjs/jwt'
import { PassportModule } from '@nestjs/passport'

@Module({
  imports: [
    PassportModule,
    JwtModule.registerAsync({
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        secret: config.get('JWT_SECRET'),
        signOptions: { expiresIn: '7d' }
      })
    }),
    UsersModule
  ],
  providers: [AuthService, JwtStrategy, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

// auth/strategies/jwt.strategy.ts
import { Injectable } from '@nestjs/common'
import { PassportStrategy } from '@nestjs/passport'
import { ExtractJwt, Strategy } from 'passport-jwt'

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private config: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: config.get('JWT_SECRET')
    })
  }

  async validate(payload: { sub: number; email: string }) {
    return { id: payload.sub, email: payload.email }
    // 返回值会挂载到 request.user
  }
}

// auth/auth.service.ts
@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService
  ) {}

  async login(user: User) {
    const payload = { sub: user.id, email: user.email }
    return {
      access_token: this.jwtService.sign(payload),
      user: { id: user.id, name: user.name, email: user.email }
    }
  }
}

拦截器与异常过滤器

ts
// 统一响应格式拦截器
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'

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

// 全局异常过滤器
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp()
    const response = ctx.getResponse()
    const status = exception.getStatus()
    const exceptionResponse = exception.getResponse()

    response.status(status).json({
      code: status,
      message: typeof exceptionResponse === 'string'
        ? exceptionResponse
        : (exceptionResponse as any).message,
      timestamp: new Date().toISOString()
    })
  }
}

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

总结

  • NestJS 的模块化架构让大型项目易于维护和测试
  • DTO + ValidationPipe 实现请求数据的自动验证和转换
  • 依赖注入让服务解耦,便于单元测试(mock 依赖)
  • 拦截器统一响应格式,异常过滤器统一错误处理
  • 配合 Swagger(@nestjs/swagger)自动生成 API 文档

系统学习 Web 前端生态,深入底层架构