1. Express.js 架构哲学
作为 Node.js 生态中应用最广泛的 Web 框架,Express.js 以"最小化设计原则"为核心,通过模块化架构实现灵活扩展。
核心设计理念
- 简约而不简单:仅提供 Web 开发的基础功能,其他能力通过中间件扩展
- 中间件驱动架构:采用洋葱模型实现请求处理流水线
- 无强制约束:不限定项目结构,开发者拥有完全自由
- 渐进式增强:可根据需求添加功能模块,避免过度设计
关键架构组件:
- 中间件系统:请求处理流水线,每个中间件可访问请求/响应对象
- 路由分发器:基于 HTTP 方法和 URL 的高效路由匹配
- 视图引擎接口:支持多种模板引擎(EJS、Pug等)
- 扩展接口:通过
app.set()/app.get()管理应用配置
安装:
npm install express
基本应用结构
const express = require('express');
const app = express();
const port = 3000;
// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 路由
app.get('/', (req, res) => {
res.send('Hello Express!');
});
// 启动服务器
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
2. 中间件
中间件类型:
-
应用级中间件:绑定到 app 实例
// 记录请求时间的应用级中间件 app.use((req, res, next) => { req.requestTime = Date.now(); console.log(`请求时间: ${req.requestTime}`); next(); // 必须调用next传递控制权 }); -
路由级中间件:绑定到路由实例
const router = express.Router(); router.use((req, res, next) => { console.log('路由中间件执行'); next(); }); -
错误处理中间件:四个参数的特殊中间件
app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('服务器错误!'); }); -
内置中间件:
app.use(express.json()); // 解析JSON请求体 app.use(express.static('public')); // 静态文件服务 -
第三方中间件:
const helmet = require('helmet'); app.use(helmet()); // 安全头部设置
中间件执行顺序:
Express 中间件按照声明顺序执行,理解这一点对于正确配置应用至关重要:
- 请求到达服务器
- 按顺序执行匹配的中间件
- 每个中间件可以修改 req/res 对象
- 中间件通过 next() 传递控制权
- 当某个中间件发送响应时,链终止
3. 路由系统深度解析
路由基础:
// 基础路由
app.get('/products', (req, res) => {
res.json([{ id: 1, name: '手机' }]);
});
// 路由参数
app.get('/products/:id', (req, res) => {
const id = req.params.id;
res.json({ id, name: `商品${id}` });
});
// 查询参数
app.get('/search', (req, res) => {
const q = req.query.q;
res.send(`搜索: ${q}`);
});
4. 请求与响应处理
请求对象 (req) :
req.params:路由参数req.query:查询字符串参数req.body:请求体内容(需要中间件解析)req.cookies:客户端 cookiesreq.headers:HTTP 请求头req.ip:客户端 IP 地址
响应对象 (res) :
res.status(code):设置状态码res.send(body):发送响应res.json(obj):发送 JSON 响应res.render(view, locals):渲染模板res.redirect(path):重定向res.set(field, value):设置响应头
// 综合使用示例
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: '用户名和密码必填' });
}
// 认证逻辑...
res.cookie('token', 'abc123', { httpOnly: true });
res.redirect('/dashboard');
});
5. Express vs Koa vs Node 深度对比
5.1 Express 与 Node.js 的关系
关系解析:
- Node.js 是运行时环境,提供 HTTP 模块等基础能力
- Express 是基于 Node.js HTTP 模块的封装框架
- Express 简化了路由、中间件等常见 Web 开发任务
5.2 Express 与 Koa 的深度对比
-
设计理念:Express.js 设计较为灵活,提供了丰富的功能和插件,适合快速开发各种类型的 Web 应用。而 Koa 是由 Express.js 的原班人马打造,它更注重简洁和优雅,采用了更现代化的异步编程方式(如 async/await),并且没有捆绑任何中间件,开发者可以根据需求自由选择和组合中间件。
-
中间件机制:Express.js 的中间件采用传统的回调函数形式,中间件之间通过next()方法传递控制权。在处理复杂的异步操作时,可能会出现回调地狱的问题。Koa 的中间件基于 async/await 语法,通过await next()实现中间件的执行和传递,代码更加简洁、易读,避免了回调地狱。
-
错误处理:在 Express.js 中,错误处理通常通过在中间件或路由处理函数中捕获错误,并传递给错误处理中间件。而 Koa 使用 try/catch 块或者在 async 函数中返回错误,通过onerror事件来统一处理错误,错误处理更加直观和方便。
Express vs Koa 核心差异:
| 特性 | Express | Koa |
|---|---|---|
| 中间件模型 | 线性链式调用 | 洋葱模型 |
| 异步处理 | 回调函数 | 原生Async/Await |
| 错误处理 | 集中式错误中间件 | Try/Catch捕获 |
| 路由系统 | 内置Router | 需koa-router |
| 请求/响应封装 | 原生对象扩展 | 统一Context对象 |
| 体积大小 | 约4.5MB | 约0.6MB |
6. Express 实战案例:RESTful API 实现
const express = require('express');
const app = express();
app.use(express.json());
// 内存数据库
let users = [
{ id: 1, name: '张三', email: 'zhang@example.com' },
{ id: 2, name: '李四', email: 'li@example.com' }
];
// 获取所有用户
app.get('/api/users', (req, res) => {
res.json({
status: 'success',
count: users.length,
data: users
});
});
// 创建新用户
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
const newUser = {
id: users.length + 1,
name,
email
};
users.push(newUser);
res.status(201).json({
status: 'success',
data: newUser
});
});
});
// 全局404处理
app.use((req, res) => {
res.status(404).json({
status: 'error',
message: '路由不存在'
});
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
status: 'error',
message: '服务器内部错误'
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
7. 总结
Express.js的优势:
- 简洁核心+丰富扩展:保持核心轻量,通过中间件提供无限扩展
- 渐进式采用路径:从简单路由到复杂应用均可胜任
- 社区驱动生态:庞大的中间件生态系统解决各种场景需求
- 文档与稳定性:优秀的文档质量和稳定的API设计
最佳实践建议:
- 使用
express.Router实现路由模块化 - 中间件按功能拆分为独立模块
- 统一错误处理机制
- 使用
helmet增强安全性 - 结合
morgan记录访问日志 - 使用
express-validator进行输入验证