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
- 异常处理:完善的异常处理机制
- 测试支持:内置测试工具,支持单元测试和集成测试
- 生态系统:丰富的插件和中间件支持
- 适用场景:大型企业级应用,需要强类型和模块化的项目