Q18: NestJS 是什么?它有什么特点?

100 阅读2分钟

Node.js 面试题详细答案 - Q18

Q18: NestJS 是什么?它有什么特点?

NestJS 概述

NestJS 是一个基于 TypeScript 的 Node.js 框架,用于构建高效、可扩展的服务器端应用程序。它结合了 OOP、FP 和 FRP 的元素。

核心特点

1. 基于 TypeScript
// 强类型支持
interface User {
  id: number
  name: string
  email: string
}

@Controller('users')
export class UsersController {
  @Get()
  findAll(): User[] {
    return [
      { id: 1, name: 'John', email: 'john@example.com' },
      { id: 2, name: 'Jane', email: 'jane@example.com' },
    ]
  }
}
2. 装饰器模式
import { Controller, Get, Post, Body, Param } from '@nestjs/common'

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

  @Get(':id')
  findOne(@Param('id') id: string) {
    return `获取用户 ${id}`
  }

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return '创建用户'
  }
}
3. 依赖注入
// 服务类
@Injectable()
export class UsersService {
  private users: User[] = []

  findAll(): User[] {
    return this.users
  }

  create(createUserDto: CreateUserDto): User {
    const user = { id: Date.now(), ...createUserDto }
    this.users.push(user)
    return user
  }
}

// 控制器注入服务
@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

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

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

模块化架构

1. 模块定义
// users.module.ts
import { Module } from '@nestjs/common'
import { UsersController } from './users.controller'
import { UsersService } from './users.service'

@Module({
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}
2. 应用模块
// app.module.ts
import { Module } from '@nestjs/common'
import { UsersModule } from './users/users.module'
import { DatabaseModule } from './database/database.module'

@Module({
  imports: [UsersModule, DatabaseModule],
  controllers: [],
  providers: [],
})
export class AppModule {}
3. 模块间通信
// 共享模块
@Module({
  providers: [DatabaseService],
  exports: [DatabaseService],
})
export class DatabaseModule {}

// 使用共享模块
@Module({
  imports: [DatabaseModule],
  providers: [UsersService],
})
export class UsersModule {}

实际应用示例

1. 基本应用结构
// main.ts
import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'

async function bootstrap() {
  const app = await NestFactory.create(AppModule)
  await app.listen(3000)
}
bootstrap()

// app.module.ts
import { Module } from '@nestjs/common'
import { UsersModule } from './users/users.module'

@Module({
  imports: [UsersModule],
})
export class AppModule {}
2. 控制器和服务
// users.controller.ts
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common'
import { UsersService } from './users.service'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

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

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

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id)
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(+id, updateUserDto)
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id)
  }
}
3. 数据传输对象
// dto/create-user.dto.ts
import { IsEmail, IsNotEmpty, IsString } from 'class-validator'

export class CreateUserDto {
  @IsString()
  @IsNotEmpty()
  name: string

  @IsEmail()
  email: string

  @IsString()
  @IsNotEmpty()
  password: string
}

中间件和守卫

1. 中间件
// 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(`${req.method} ${req.url} - ${new Date()}`)
    next()
  }
}

// 应用中间件
@Module({
  // ...
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*')
  }
}
2. 守卫
// auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest()
    const token = request.headers.authorization

    if (!token) {
      return false
    }

    // 验证令牌逻辑
    return this.validateToken(token)
  }

  private validateToken(token: string): boolean {
    // 令牌验证逻辑
    return token === 'valid-token'
  }
}

// 使用守卫
@Controller('users')
@UseGuards(AuthGuard)
export class UsersController {
  // ...
}

数据库集成

1. TypeORM 集成
// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string

  @Column()
  email: string

  @Column()
  password: string
}

// users.service.ts
import { Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User } from './user.entity'

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

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

  async create(createUserDto: CreateUserDto): Promise<User> {
    const user = this.usersRepository.create(createUserDto)
    return this.usersRepository.save(user)
  }
}
2. 数据库模块
// database.module.ts
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { User } from './entities/user.entity'

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'test',
      entities: [User],
      synchronize: true,
    }),
  ],
})
export class DatabaseModule {}

异常处理

1. 自定义异常
// user-not-found.exception.ts
import { HttpException, HttpStatus } from '@nestjs/common'

export class UserNotFoundException extends HttpException {
  constructor(id: number) {
    super(`用户 ID ${id} 不存在`, HttpStatus.NOT_FOUND)
  }
}

// 使用异常
@Injectable()
export class UsersService {
  async findOne(id: number): Promise<User> {
    const user = await this.usersRepository.findOne(id)
    if (!user) {
      throw new UserNotFoundException(id)
    }
    return user
  }
}
2. 全局异常过滤器
// http-exception.filter.ts
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from '@nestjs/common'
import { Request, Response } from 'express'

@Catch(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.message,
    })
  }
}

// 应用全局过滤器
app.useGlobalFilters(new HttpExceptionFilter())

测试支持

1. 单元测试
// users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing'
import { UsersService } from './users.service'

describe('UsersService', () => {
  let service: UsersService

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UsersService],
    }).compile()

    service = module.get<UsersService>(UsersService)
  })

  it('should be defined', () => {
    expect(service).toBeDefined()
  })

  it('should return all users', () => {
    const result = service.findAll()
    expect(result).toBeDefined()
  })
})
2. 集成测试
// users.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing'
import { UsersController } from './users.controller'
import { UsersService } from './users.service'

describe('UsersController', () => {
  let controller: UsersController
  let service: UsersService

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [UsersController],
      providers: [UsersService],
    }).compile()

    controller = module.get<UsersController>(UsersController)
    service = module.get<UsersService>(UsersService)
  })

  it('should be defined', () => {
    expect(controller).toBeDefined()
  })
})

总结

  • NestJS 特点:基于 TypeScript,支持装饰器,依赖注入
  • 模块化架构:清晰的模块结构,便于组织和维护
  • 装饰器模式:简化路由和中间件定义
  • 依赖注入:自动管理依赖关系,提高代码可测试性
  • 数据库集成:支持 TypeORM、Mongoose 等 ORM
  • 异常处理:完善的异常处理机制
  • 测试支持:内置测试工具,支持单元测试和集成测试
  • 生态系统:丰富的插件和中间件支持
  • 适用场景:大型企业级应用,需要强类型和模块化的项目