1. 内容整体设计与思路拆解
凡是写过原生 Node.js 接口的人,应该都有过这种体验:用http.createServer创建一个服务,然后对着req.url做字符串判断,再手工设置响应头,把返回数据JSON.stringify之后塞进res.end。一个两个接口还好,接口一多就开始混乱,路由规则、参数解析、错误处理、日志这些全混在一起,改一处漏三处。Express 框架解决的就是这个核心痛点:在 Node.js 原生的 HTTP 模块之上,提供一套简洁的路由定义、中间件机制和请求响应封装,让你用几行代码就能把业务逻辑清晰地组织起来。
很多人问,Express 都出来这么多年了,还有必要学吗?我的回答是:太有必要了。现阶段 Express 依然是 Node.js 生态里用户基数最大、资料最全、上手门槛最低的 Web 框架。它不强迫你使用 TypeScript,不引入依赖注入、装饰器这些概念,就是老老实实的 JavaScript 函数式写法。正因为它简单,你才能把注意力集中在 HTTP 协议本身、路由设计与中间件思想上,这些恰恰是后续学习 Koa、Fastify、NestJS 甚至任何后端框架的基础。这篇文章适合刚接触 Node.js 想写后端接口的人,也适合那些已经会写几个接口但对路由、中间件原理一知半解,想系统梳理一遍的开发者。
1.1 Express 的设计哲学:小而精的“路由 + 中间件”
Express 的核心抽象只有两个:路由和中间件。路由解决的是“哪个请求该交给哪个函数处理”,中间件解决的是“请求到达正式处理函数之前和之后,需要执行哪些通用逻辑”。这两个概念相互交织,构成了 Express 的全部骨架。
先说路由。你可以把路由想象成一份“菜单”:GET /api/users对应获取用户列表,POST /api/users对应创建用户,PUT /api/users/:id对应更新某个用户。Express 通过app.get()、app.post()这种直观的方法名把 HTTP 动词和路径绑定到处理函数上,不需要自己写 if-else 去解析 URL。路径中间还可以用:id这种动态参数标记,Express 会自动从 URL 里提取出来放在req.params里。
再说中间件。这有点像工厂流水线上的工位,每个工位只做一件固定的事:有的解析请求体,有的打日志,有的检查用户有没有登录,有的给响应头加 CORS 字段。请求从进入工厂开始,按顺序经过这些工位,最后到达终点即路由处理函数。处理完毕后,响应原路返回,也可以经过后面的工位再做统一处理,比如统一压缩、统一记录响应时间。这种模式的好处是极具复用性,逻辑解耦,想增加一个功能,只需在流水线上插入一个工位,不必改动其他代码。
const express = require('express'); const app = express(); // 中间件:打印请求方法、路径和耗时 app.use((req, res, next) => { const start = Date.now(); console.log(`${req.method} ${req.url}`); next(); console.log(`耗时:${Date.now() - start}ms`); }); // 路由:返回用户列表 app.get('/api/users', (req, res) => { res.json([{ id: 1, name: '张三' }]); });这段代码虽然短,但完整展示了中间件和路由的协作:先用app.use注册一个通用中间件,然后在中间件里调用next()把控制权交给下一个处理者;路由处理函数用res.json直接返回结构化数据。理解了这个流程,后面所有复杂功能都是在这个基础上加料。
1.2 为什么选择 Express,而不是 Koa 或 Fastify
这几年 Node.js 框架越来越多,常被拿来和 Express 比较的是 Koa 和 Fastify。Koa 是 Express 原班人马打造的,特点是使用了 async/await 和更扁平的中间件模型;Fastify 则以高性能和内置 schema 校验著称。那为什么很多项目仍然选 Express?
最直接的原因是稳定和企业级认可。Express 从 2010 年诞生至今,经历了大量生产环境检验,生态里所有中间件几乎都有 Express 版本,团队招人也好招。Koa 虽然中间件模型更优雅,但生态相对小,很多功能需要自己拼装;Fastify 性能虽好,但它的插件体系和 JSON Schema 校验要求一开始就要按照它的思路设计,对于快速开发服务的场景反而有点重。
我的个人建议是:如果你是在校学生、刚转行做后端、或者要快速交付一个中小型项目,直接用 Express 准没错;等你有了一定经验,再去学 Koa 理解中间件模型的差异,或者学 Fastify 体会性能优化的空间,思路都会举一反三。框架只是工具,重要的是吃透 HTTP 请求处理的底层逻辑。
1.3 一个请求从进入到返回的完整旅程
为了后续实操不迷茫,我们先用文字走一遍请求在 Express 里的生命周期。假设前端发送了一个POST /api/login请求,带有一个 JSON 请求体{"username":"admin","password":"123456"}:
- Node.js 原生服务器接收到 HTTP 请求,最终交给 Express 的
app处理。 - Express 进入内置的中间件队列,先经过
express.json()中间件,它读取请求体里的原始数据,按照 JSON 格式解析成对象,挂到req.body上。 - 继续往后走,可能会经过你自己的日志中间件、鉴权中间件(当然登录接口一般不需要鉴权,这里只是举例)。
- 当请求到了某个路由匹配阶段,Express 会按注册顺序比对路径和方法,命中后执行路由处理函数,从
req.body里取出用户名密码,去数据库查询并校验。 - 校验成功,处理函数调用
res.json({ token: 'xxx' }),Express 在底层帮你把对象序列化、设置Content-Type: application/json; charset=utf-8,发送给客户端。 - 响应结束后,如果后面还有中间件,仍然可以执行收尾逻辑,比如记录响应状态码。
整个过程最需要注意的是“中间件顺序”。在 Express 里,中间件的注册顺序几乎决定了谁能生效,后注册的中间件可能永远等不到先注册的next()被调用,这会在后文常见问题里专门说。先把这张图印在脑子里,接下来我们动手搭建项目。