前言
写 Node 后端很多人从 Express 上手,写小项目很爽,一旦业务膨胀,路由、业务逻辑、数据操作全部堆在一起,代码杂乱难维护,不好做单元测试。
NestJS 是一套基于 TypeScript 的企业级 Node 后端框架,把模块化、MVC 分层、依赖注入、装饰器、经典设计模式全部融入框架本身,非常适合开发 API 服务、微服务、AI 底层服务。
划重点:不要混淆!
- NestJS:Node 后端框架(本文)
- NextJS:React 全栈框架,二者毫无关系
后端开发主要做什么
- 对外提供 RESTful API,对接前端做 Web 开发
- 系统集成、并发处理、底层服务、AI Infra 基建
- 业务拆分,搭建微服务架构
环境安装与项目启动
bash
运行
bash
# 全局安装nest脚手架
npm i -g @nestjs/cli
# 创建新项目
nest new hello
# 启动开发环境
nest start
初始核心目录
src/main.ts:项目入口文件,程序启动从这里开始app.module.ts:根模块,整个应用的组装调度中心
理解工厂模式:看懂 NestFactory
工厂模式是 23 种设计模式中最重要的模式之一,核心思想:面向接口编程,把对象创建和业务使用解耦,使用者不用关心实例化细节。
通俗比喻:想喝奶茶不用自己买原料熬煮,直接找蜜雪冰城(工厂)下单,工厂帮你生产好饮品,你直接使用。Nest 中的 NestFactory 就是这个 "蜜雪冰城工厂",我们不需要手动 new 一大堆底层组件,调用NestFactory.create()就拿到应用实例。
蜜雪冰城工厂模式示例代码
javascript
运行
typescript
// 产品1:冰淇淋
class IceCream {
constructor() {
this.name = '冰激凌';
this.price = 3;
}
// 统一接口,所有产品都实现show方法
show() {
console.log(`${this.name},${this.price}`);
}
}
// 产品2:柠檬水
class LemonTea {
constructor() {
this.name = '柠檬水';
this.price = 4;
}
show() {
console.log(`${this.name},${this.price}`);
}
}
// 产品3:珍珠奶茶
class MilkTea {
constructor() {
this.name = '珍珠奶茶';
this.price = 8;
}
show() {
console.log(`${this.name},${this.price}`);
}
}
// ✅ 工厂类:统一生产实例,使用者只和工厂打交道
class MiXueFactory {
static create(type) {
switch (type) {
case 'ice':
return new IceCream();
case 'tea':
return new LemonTea();
case 'milk':
return new MilkTea();
}
}
}
// 使用方,不需要手动new各个产品
const drink1 = MiXueFactory.create('ice');
drink1.show();
const drink2 = MiXueFactory.create('tea');
drink2.show();
const drink3 = MiXueFactory.create('milk');
drink3.show();
好处:新增饮品,只需要新增产品类,修改工厂,调用方代码完全不用改动,实现解耦。
NestJS 高度模块化,MVC 分层
Nest 有强约定,一个业务模块固定三件套:
xx.module.ts:模块组装层,注册 controller、providerxx.controller.ts:控制器,接收 http 请求,参数处理,返回响应,禁止写复杂业务xx.service.ts:服务层 provider,处理核心业务逻辑、数据操作
两个核心概念
- @Injectable() :装饰器,把类交给 Nest 容器管理,开启依赖注入,不需要手动
new,构造函数直接注入使用。 - 装饰器模式 :不修改原有类内部代码,通过
@符号动态给类、方法增加能力,比如绑定路由前缀、请求方法。
铁律:Controller 只负责接收转发请求,业务逻辑、数据操作全部下沉 Service 层。
Nest 异常处理(面试高频)
面试题:NestJS 中如何处理后端报错?
原生 JS 我们会用try catch捕获异常,而 Nest 内置大量标准化异常类,例如NotFoundException。直接抛出框架异常,框架自动包装统一格式返回,自动带上statusCode、message,前端解析更方便,后续还可以配合全局异常过滤器统一处理。
Todo CRUD 完整实战
实现待办事项增删改查,内存数组模拟数据库,企业项目替换成 ORM 即可。
todos.service.ts 业务服务层
typescript
运行
typescript
import { Injectable, NotFoundException } from '@nestjs/common';
// Todo数据类型定义
export interface Todo {
id: number;
title: string;
complete: boolean;
}
// 模拟数据库,真实项目替换数据库
const todos: Todo[] = [
{ id: 1, title: '学习 NestJS', complete: false },
{ id: 2, title: '学习 CRUD', complete: true },
];
let nextId = 3;
// ✅ @Injectable 交给Nest容器管理,支持依赖注入
@Injectable()
export class TodosService {
// 查询全部待办
findAll(): Todo[] {
return todos;
}
// 根据id查询单条
findOne(id: number): Todo {
const todo = todos.find((t) => t.id === id);
// 业务容错,数据不存在抛出404标准异常
if (!todo) throw new NotFoundException(`Todo ${id} 不存在`);
return todo;
}
// 新增待办
create(title: string): Todo {
const todo: Todo = { id: nextId++, title, complete: false };
todos.push(todo);
return todo;
}
// 删除待办
remove(id: number): void {
const index = todos.findIndex((t) => t.id === id);
if (index === -1) throw new NotFoundException(`Todo ${id}不存在`);
todos.splice(index, 1);
}
// 更新待办,局部更新
update(id: number, patch: Partial<Todo>): Todo {
// 复用查询逻辑,自带不存在校验,减少重复代码
const todo = this.findOne(id);
Object.assign(todo, patch);
return todo;
}
}
todos.controller.ts 控制器层
typescript
运行
less
import { Controller, Get, Post, Param, Body, Delete, Put } from '@nestjs/common';
import { TodosService } from './todos.service';
import { type Todo } from './todos.service';
// ✅ 路由前缀,所有接口前缀 /todos
@Controller('todos')
export class TodosController {
// ✅ 依赖注入,nest自动实例化service,不用手动new
constructor(private readonly todosService: TodosService) {}
// GET /todos 获取全部
@Get()
findAll(): Todo[] {
console.log('/todos controller');
return this.todosService.findAll();
}
// GET /todos/:id 获取单条
@Get(':id')
findOne(@Param('id') id: string): Todo {
console.log(id);
return this.todosService.findOne(Number(id));
}
// POST /todos 创建待办
@Post()
create(@Body('title') title: string): Todo {
return this.todosService.create(title);
}
// DELETE /todos/:id 删除待办
@Delete(':id')
remove(@Param('id') id: string): { message: string } {
this.todosService.remove(Number(id));
return { message: '删除成功' };
}
// PUT /todos/:id 更新待办
@Put(':id')
update(@Param('id') id: string, @Body() patch: Partial<Todo>): Todo {
return this.todosService.update(Number(id), patch);
}
}
todos.module.ts 模块组装
typescript
运行
typescript
import { Module } from '@nestjs/common';
import { TodosController } from './todos.controller';
import { TodosService } from './todos.service';
// 注册本模块控制器和服务提供者
@Module({
controllers: [TodosController],
providers: [TodosService],
})
export class TodosModule {}
⚠️ 注意:需要把
TodosModule导入根模块AppModule的imports数组中,接口才会生效。
核心要点总结
- NestJS 基于 TS,主打模块化、依赖注入、装饰器,用于企业级 Node 后端开发。
- 分层原则:Controller 负责接收 http 请求,Service 实现业务逻辑,职责隔离。
- 工厂模式:对象创建与业务逻辑解耦,
NestFactory就是典型实现。 - 异常处理优先使用框架内置异常类,统一接口返回格式。
@Injectable()+ 构造函数注入,省去手动实例化,便于单元测试。