Node.js 网络编程:Express 与 Koa 框架
Node.js 让 JavaScript 能在服务器端运行,而 Express 和 Koa 是两个最流行的轻量级 Web 框架。它们都基于中间件机制处理请求和响应,但设计理念和使用方式有明显差异。本文通过具体操作步骤,手把手教你搭建、对比并选择适合的框架。
安装与初始化项目
创建一个新目录用于实验:
mkdir express-koa-compare
cd express-koa-compare
初始化 Node.js 项目(一路回车即可):
npm init -y
安装 Express 和 Koa(先同时安装,后续分别使用):
npm install express koa
用 Express 搭建一个简单服务
新建文件 app-express.js:
const express = require('express');
const app = express();
const PORT = 3001;
// 中间件:解析 JSON 请求体
app.use(express.json());
// 路由:返回欢迎信息
app.get('/', (req, res) => {
res.send('Hello from Express!');
});
// 路由:接收 POST 请求
app.post('/echo', (req, res) => {
res.json({ received: req.body });
});
// 启动服务器
app.listen(PORT, () => {
console.log(`Express server running on http://localhost:${PORT}`);
});
```
**运行**该服务:
```bash
node app-express.js
```
**测试**功能:
- 在浏览器访问 `http://localhost:3001`,应看到文字 "Hello from Express!"。
- 使用命令行发送 POST 请求验证数据回显:
```bash
curl -X POST http://localhost:3001/echo \
-H "Content-Type: application/json" \
-d '{"name": "Alice"}'
```
预期返回:`{"received":{"name":"Alice"}}`。
---
## 用 Koa 搭建等效服务
Koa 不内置路由或请求体解析,需额外安装中间件。**先安装**所需依赖:
```bash
npm install koa-router koa-bodyparser
```
**新建**文件 `app-koa.js`:
```javascript
const Koa = require('koa');
const Router = require('koa-router');
const bodyParser = require('koa-bodyparser');
const app = new Koa();
const router = new Router();
const PORT = 3002;
// 中间件:解析 JSON 请求体
app.use(bodyParser());
// 路由:返回欢迎信息
router.get('/', (ctx) => {
ctx.body = 'Hello from Koa!';
});
// 路由:接收 POST 请求
router.post('/echo', (ctx) => {
ctx.body = { received: ctx.request.body };
});
// 注册路由
app.use(router.routes());
// 启动服务器
app.listen(PORT, () => {
console.log(`Koa server running on http://localhost:${PORT}`);
});
运行该服务:
node app-koa.js
测试功能:
- 浏览器访问
http://localhost:3002,应显示 "Hello from Koa!"。 - 发送 POST 请求:
curl -X POST http://localhost:3002/echo \
-H "Content-Type: application/json" \
-d '{"name": "Bob"}'
预期返回:{"received":{"name":"Bob"}}。
核心差异对比
虽然两个服务功能相同,但实现逻辑和架构思想不同。关键区别如下:
| 特性 | Express | Koa |
|---|---|---|
| 中间件模型 | 线性回调(Error-first callback) | 基于 async/await 的洋葱模型 |
| 内置功能 | 内置路由、静态文件、请求体解析 | 极简核心,功能靠中间件扩展 |
| 错误处理 | 需单独定义错误处理中间件 | 可直接用 try/catch 捕获异步错误 |
| 上下文对象 | req 和 res 分离 |
统一为 ctx(包含 request 和 response) |
| 学习曲线 | 初学者友好,开箱即用 | 需理解中间件组合逻辑 |
编写可复用的中间件
中间件是这两个框架的核心。下面分别展示如何编写一个记录请求时间的中间件。
Express 版本
修改 app-express.js,在 app.use(express.json()) 前插入:
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} - ${duration}ms`);
});
next();
});
```
### Koa 版本
**修改** `app-koa.js`,在 `app.use(bodyParser())` 前插入:
```javascript
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
console.log(`${ctx.method} ${ctx.path} - ${duration}ms`);
});
重启两个服务后,每次请求都会在终端打印耗时。
异步错误处理实战
模拟一个可能失败的操作(如数据库查询),看两者如何处理异常。
Express 错误处理
添加以下路由到 app-express.js:
app.get('/error', (req, res, next) => {
setTimeout(() => {
try {
throw new Error('Database timeout');
} catch (err) {
next(err); // 将错误传递给错误处理中间件
}
}, 100);
});
// 错误处理中间件(必须放在所有路由之后)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
访问 http://localhost:3001/error,页面显示 "Something broke!",终端打印错误栈。
Koa 错误处理
添加以下代码到 app-koa.js(放在 app.use(router.routes()) 之前):
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
console.error(err.stack);
ctx.status = 500;
ctx.body = 'Something broke!';
}
});
router.get('/error', async (ctx) => {
await new Promise((resolve) => setTimeout(resolve, 100));
throw new Error('Database timeout');
});
访问 http://localhost:3002/error,效果与 Express 一致,但代码更简洁——无需额外中间件,直接用 try/catch 包裹 next() 即可捕获下游所有异步错误。
如何选择?
选用 Express 如果:
- 你需要快速构建原型或小型应用。
- 团队熟悉传统回调风格。
- 依赖大量现成的 Express 中间件(如
express-session、helmet)。
选用 Koa 如果:
- 你希望代码更现代、更易测试(async/await 天然支持)。
- 你追求极简架构,愿意按需引入功能。
- 你计划长期维护项目,看重错误处理的清晰性。
两者都能胜任 Web API、微服务或 SSR 应用。Express 生态更成熟,Koa 更面向未来。对于新项目,若团队已掌握 async/await,Koa 往往带来更干净的代码结构。

暂无评论,快来抢沙发吧!