2024 版:Node.js+Express+Koa2+Nest.js 开发服务端
2024 版:Node.js + Express + Koa2 + Nest.js 开发服务端完全指南
一、从“会写接口”到“会设计系统”
2024 年,Node.js 早已不再是“前端工程师顺手写接口”的辅助工具。它凭借事件驱动、非阻塞 I/O 的特性,在企业级服务端、BFF 层、API 网关、实时通信等场景中占据了稳固的位置。然而,服务端开发的挑战早已不是“能不能写出接口”,而是“能不能构建稳定、可维护、可扩展的系统”。
本文将以一个博客项目为线索,从 Node.js 原生开发开始,依次用 Express、Koa2、Nest.js 重构,带你理解三种框架各自解决什么问题,以及如何根据场景做出选择。
服务端的核心职责可以用一句话概括:接收前端请求,处理业务逻辑,返回结果。具体而言,它承担着接口开发、业务规则实现、权限与安全、数据存储、服务器运维、第三方对接六大职责。一次完整的请求会经历:前端发起 → 负载均衡 → 网关鉴权 → 服务接收 → 参数校验 → 业务处理 → 读写数据库 → 组装返回 → 前端渲染。关键业务逻辑必须放在服务端,因为前端代码可以被篡改。
二、Node.js 原生开发:理解本质
在学习框架之前,先用原生 Node.js 写一个简单的 HTTP 服务,有助于理解框架到底封装了什么。
javascript
const http = require(‘http’);
const url = require(‘url’);
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method.toUpperCase();
// 手动路由
if (path === ‘/api/articles’ && method === ‘GET’) {
res.writeHead(200, { ‘Content-Type’: ‘application/json’ });
res.end(JSON.stringify({ code: 0, data: [] }));
} else if (path === ‘/api/articles’ && method === ‘POST’) {
let body = ‘’;
req.on(‘data’, chunk => body += chunk);
req.on(‘end’, () => {
const article = JSON.parse(body);
res.writeHead(201, { ‘Content-Type’: ‘application/json’ });
res.end(JSON.stringify({ code: 0, data: article }));
});
} else {
res.writeHead(404, { ‘Content-Type’: ‘application/json’ });
res.end(JSON.stringify({ code: 404, msg: ‘Not Found’ }));
}
});
server.listen(3000, () => console.log(‘Server running on port 3000’));
这段代码暴露了原生开发的痛点:手动解析 URL、手动处理请求体、手动设置响应头、没有中间件机制、没有统一的错误处理。框架的价值,正是把这些重复劳动抽象出来。
三、Express:生态之王
核心特点
Express 是 Node.js 最流行、最成熟的 Web 框架。它的核心是线性中间件模型:请求依次经过一系列中间件函数,每个中间件可以决定继续传递、结束响应或抛出错误。
优点:生态最丰富(社区中间件超过 5000 个)、学习成本极低、文档完善、灵活自由。缺点:回调地狱问题(尽管 async/await 可缓解)、缺乏内置错误处理规范、项目结构需自行设计,大型项目容易失控。
实践示例
javascript
const express = require(‘express’);
const app = express();
app.use(express.json());
// 日志中间件
app.use((req, res, next) => {
console.log([${new Date().toISOString()}] ${req.method} ${req.url});
next();
});
// 路由与业务逻辑混写(初期可以,但需警惕)
const articles = [];
app.get(‘/api/articles’, (req, res) => {
res.json({ code: 0, data: articles });
});
app.post(‘/api/articles’, (req, res) => {
const { title, content } = req.body;
if (!title || !content) {
return res.status(400).json({ code: 1, msg: ‘参数错误’ });
}
const article = { id: Date.now(), title, content, createdAt: new Date() };
articles.push(article);
res.status(201).json({ code: 0, data: article });
});
// 错误处理中间件(4个参数)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ code: 500, msg: ‘服务器内部错误’ });
});
app.listen(3000);
进阶建议
Express 的自由度是一把双刃剑。进阶使用时,必须建立分层思维:把路由、控制器、服务、数据访问拆开。同时补齐安全头(helmet)、限流、日志、参数校验(express-validator / zod)和统一异常处理。
四、Koa2:优雅的洋葱模型
核心特点
Koa2 由 Express 原班人马打造,采用洋葱模型中间件,配合 async/await 彻底解决了回调地狱问题。请求像穿过洋葱一样,先由外到内逐层进入,再由内到外逐层返回。
javascript
const Koa = require(‘koa’);
const Router = require(‘@koa/router’);
const bodyParser = require(‘koa-bodyparser’);
const app = new Koa();
const router = new Router();
// 洋葱模型演示
app.use(async (ctx, next) => {
console.log(‘1. 请求进入第一层’);
await next();
console.log(‘6. 响应返回第一层’);
});
app.use(async (ctx, next) => {
console.log(‘2. 进入第二层’);
await next();
console.log(‘5. 第二层返回’);
});
app.use(async (ctx, next) => {
console.log(‘3. 核心处理逻辑’);
ctx.body = ‘Hello’;
console.log(‘4. 处理完成’);
});
app.use(bodyParser());
router.get(‘/api/articles’, async (ctx) => {
ctx.body = { code: 0, data: [] };
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000);
执行顺序:1 → 2 → 3 → 4 → 5 → 6。await next() 让外层中间件能在内层执行完毕后继续处理,这对日志记录、性能监控、错误捕获非常有用。
适用场景与代价
Koa2 更轻、更现代,性能优于 Express。但它的“轻”意味着路由、body 解析、安全头全部需要自行安装。Koa 的生态不如 Express 丰富,安全配置完全依赖开发者记得添加哪些包。它适合追求精细中间件控制、有一定架构能力的中小型项目团队。
五、Nest.js:企业级架构
核心特点
Nest.js 是受 Angular 启发的企业级框架,TypeScript 优先,提供模块、依赖注入、装饰器、AOP 等能力。它默认基于 Express(也可切换 Fastify),但在此基础上构建了一套完整的架构范式。
核心概念:
Module(模块):应用的基本组织单元,如
UserModule、ArticleModuleController(控制器):处理 HTTP 请求,定义路由
Service(服务):业务逻辑层,通过依赖注入被控制器使用
Guard(守卫):权限校验
Interceptor(拦截器):请求/响应前后的横切逻辑
Pipe(管道):参数校验与转换
Filter(过滤器):异常处理
实践示例
typescript
// article.controller.ts
@Controller(‘articles’)
export class ArticleController {
constructor(private readonly articleService: ArticleService) {}
@Get()
findAll(): Promise<Article[]> {
return this.articleService.findAll();
}
@Post()
@UsePipes(new ValidationPipe())
create(@Body() dto: CreateArticleDto): Promise {
return this.articleService.create(dto);
}
}
typescript
// article.service.ts
@Injectable()
export class ArticleService {
private articles: Article[] = [];
findAll(): Article[] { return this.articles; }
create(dto: CreateArticleDto): Article {
const article = { id: Date.now(), …dto };
this.articles.push(article);
return article;
}
}
typescript
// app.module.ts
@Module({
imports: [],
controllers: [ArticleController],
providers: [ArticleService],
})
export class AppModule {}
优势与代价
Nest.js 的优势在于架构清晰、强制分层、可测试性强,适合大型团队协作和复杂业务系统。它内置了对 GraphQL、WebSocket、微服务、任务调度的支持,与 TypeORM/Prisma 集成良好。
代价是学习曲线陡峭:概念多(模块、守卫、拦截器、管道、过滤器),抽象层次高。小项目使用 Nest.js 会显得臃肿,团队需要熟悉 TypeScript 和依赖注入的思想才能发挥其价值。
六、三大框架横向对比
| 维度 | Express | Koa2 | Nest.js |
|---|---|---|---|
| 设计理念 | 极简、灵活、无约束 | 轻量、优雅、洋葱模型 | 企业级、结构化、约定优先 |
| 中间件模型 | 线性队列 | 洋葱模型 | 模块 + 中间件 + 管道 |
| TypeScript 支持 | 需额外配置 | 需额外配置 | 原生支持 |
| 依赖注入 | 无 | 无 | 内置 DI 容器 |
| 学习曲线 | 最低 | 中等 | 较高 |
| 生态丰富度 | 最丰富 | 较小 | 中等(官方维护好) |
| 适用场景 | 快速原型、简单 API、内部工具 | 中小型 API、追求代码优雅 | 大型企业级、微服务、复杂业务 |
| 性能 | 基准水平 | 略优于 Express | 接近 Express(取决于适配器) |
优先选 Express:快速原型开发、小型项目、团队 Node.js 经验有限、需要大量现成中间件。
优先选 Koa2:追求代码简洁优雅、需要精细控制中间件执行流程、中小型 API 服务、团队熟悉 async/await。
优先选 Nest.js:大型企业级项目、团队使用 TypeScript、需要微服务/GraphQL/WebSocket、重视架构规范与长期可维护性。
七、安全:所有框架的共同短板
一个容易被忽视的事实是:Express、Koa、Nest.js 默认都不启用安全头、CSRF 保护或输入校验。
Express 官方文档明确建议使用
helmet设置约 13 个安全响应头。CSRF 中间件csurf已被废弃且存在未修复漏洞,需改用csrf-csrf等替代方案。输入校验完全依赖第三方库。Nest.js 的
ValidationPipe配合class-validator提供了类型化的校验能力,但默认不启用,需要在main.ts中手动注册app.useGlobalPipes(new ValidationPipe())。
实践建议:无论选择哪个框架,生产环境前必须补齐:安全头(helmet)、CSRF 保护、输入校验、限流、日志记录。
八、2024 年后端进阶路线
从 Express 到 Koa2 再到 Nest.js,本质上是从“会写接口”走向“会设计系统”。框架只是入口,真正决定后端水平的是架构能力与工程素养。
2024 年值得补齐的核心能力:
TypeScript:类型安全不再“可选”,而是工程化的基础
API 设计:RESTful 规范、版本管理、错误码设计
数据库:MySQL/MongoDB + ORM(Sequelize/TypeORM/Prisma),连接池与查询优化
缓存:Redis 的使用场景与策略
鉴权授权:JWT、Session、OAuth2、RBAC
安全防护:XSS、SQL 注入、CSRF、限流、接口防刷
测试:单元测试、集成测试、E2E 测试
部署运维:Docker、PM2、Nginx、CI/CD
可观测性:日志(pino/winston)、指标、链路追踪
没有最好的框架,只有最合适的框架。Express 用于快速搭建内部工具,Koa2 用于轻量级 BFF 或网关,Nest.js 用于核心业务与微服务——它们可以在同一个系统中各司其职。理解运行时、网络、数据和部署的本质,比死记某个框架的 API 重要得多。
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu