Express框架快速上手:中间件、路由与错误处理
预计时间:1-2 天(了解即可)
🎯 本章目标
理解 Express 的中间件机制------这是所有 Node.js Web 框架的核心原理,也是理解 NestJS 的基础。
1. Express 是什么
ini
Express = 极简的 HTTP 请求处理框架
核心概念:路由 + 中间件 + 请求/响应对象
与 Spring MVC 对比
| Spring MVC | Express |
|---|---|
@RequestMapping |
app.get/post/put/delete() |
Filter |
中间件 |
@RequestBody |
req.body |
@RequestParam |
req.query |
@PathVariable |
req.params |
ResponseEntity |
res.status().json() |
2. 基础使用
bash
pnpm add express
pnpm add -D @types/express
typescript
import express, { Request, Response, NextFunction } from 'express';
const app = express();
// 解析 JSON 请求体
app.use(express.json());
// 最基础的路由
app.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date() });
});
// 带参数的路由
app.get('/api/users/:id', (req, res) => {
const { id } = req.params; // 路径参数
const { include } = req.query; // 查询参数
res.json({ id, include });
});
// POST 请求
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
// 保存用户...
res.status(201).json({ id: 1, name, email });
});
app.listen(3000, () => console.log('Server on port 3000'));
3. 中间件(核心概念)
中间件执行流程
scss
请求 → [中间件1] → [中间件2] → [路由处理器] → 响应
↓ ↓
next() next()
typescript
// 自定义中间件:请求日志
function requestLogger(req: Request, res: Response, next: NextFunction) {
console.log(`${new Date().toISOString()} ${req.method} ${req.url}`);
next(); // 必须调用 next() 传递控制权!
}
app.use(requestLogger); // 注册中间件
// 中间件:鉴权
function authMiddleware(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Unauthorized' }); // 提前返回,不调用 next()
}
// 验证 token...
(req as any).user = decodedUser;
next();
}
// 只对特定路由应用中间件
app.use('/api/protected', authMiddleware);
内置中间件
typescript
app.use(express.json()); // 解析 JSON body
app.use(express.urlencoded({ extended: true })); // 解析表单 body
app.use(express.static('public')); // 静态文件服务
错误处理中间件(4个参数)
typescript
// 错误处理中间件必须放在所有路由之后
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});
4. 路由组织(Router)
typescript
import { Router } from 'express';
const userRouter = Router();
userRouter.get('/', (req, res) => { /* 列表 */ });
userRouter.get('/:id', (req, res) => { /* 详情 */ });
userRouter.post('/', (req, res) => { /* 创建 */ });
userRouter.put('/:id', (req, res) => { /* 更新 */ });
userRouter.delete('/:id', (req, res) => { /* 删除 */ });
// 挂载到主应用
app.use('/api/users', userRouter);
5. 完整项目示例
typescript
// src/app.ts
import express from 'express';
import { userRouter } from './routes/user.routes.js';
import { errorHandler } from './middlewares/error.middleware.js';
import { requestLogger } from './middlewares/logger.middleware.js';
const app = express();
app.use(express.json());
app.use(requestLogger);
app.use('/api/users', userRouter);
app.use(errorHandler);
export default app;
typescript
// src/index.ts
import app from './app.js';
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
6. 为什么选择 NestJS 而不是 Express
| Express | NestJS | |
|---|---|---|
| 架构 | 无约束,自由发挥 | 模块化,强约束 |
| 依赖注入 | ❌ 手动 | ✅ 内置 |
| TypeScript | 可选 | 原生支持 |
| 学习曲线 | 低 | 中等(但 Java 开发者觉得熟悉) |
| 适合项目 | 小项目、快速原型 | 企业级应用 |
| 生态 | 大量第三方中间件 | 内置 + 官方集成包 |
建议:用 Express 了解中间件原理,用 NestJS 做正式项目。
下一步:NestJS入门