Express 5(2024 年 9 月发布的正式版本)是其久候多年的重大版本更新。它移除了对 Node 旧版本的兼容、升级了路由底层(切换到新版 path-to-regexp),并原生支持 async 错误处理。若你的项目仍停留在 Express 4,理解这些差异能帮你平稳升级。
| 改进 | Express 4 | Express 5 |
|---|---|---|
| 异步错误处理 | 需手动 try/catch + next(err) | async 路由抛错自动进入错误中间件 |
| 路径匹配库 | path-to-regexp@0.x | path-to-regexp@8.x(更现代、更安全) |
| Node 版本 | 低至 Node 0.10 | 要求 Node >= 18 |
| 委派功能 | res.sendfile | 统一 res.sendFile |
| 内部路由属性 | 可访问 app.router | 移除,路由器改为内部实现(app._router 仅限调试) |
最关键:Express 5 让 async Handler 抛出的 Promise 拒绝能被自动捕获,彻底告别「异步错误静默吞掉」的坑。
// Express 5:无需包装,抛出的错误自动进入错误中间件
app.get("/async", async (req, res) => {
const data = await fetchData();
if (!data) throw new Error("数据加载失败"); // 自动被错误中间件捕获
res.json(data);
});
// Express 4 则需要手动处理(对比)
app.get("/async", async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (err) {
next(err);
}
});这意味着可以大幅简化代码,去掉到处可见的 asyncHandler 包装器。
当内容体解析失败(如非法 JSON)时,Express 5 会自动将错误传给错误处理中间件:
app.use(express.json());
app.post("/data", (req, res) => res.json({ received: req.body }));
// 错误处理中间件可捕获 body 解析错误
app.use((err, req, res, next) => {
if (err.type === "entity.parse.failed") {
return res.status(400).json({ error: "请求体不是合法 JSON" });
}
next(err);
});// 支持通配匹配的 content-type 通配符
app.use(express.json({ type: "*/json" }));
// 可指定 strict 行为
app.use(express.json({ strict: true })); // 仅接受数组和对象Express 5 使用新版 path-to-regexp@8,路由参数语法与 4 有差异:
| 场景 | Express 4 | Express 5 |
|---|---|---|
| 简单参数 | /:id | /:id(不变) |
| 可选参数 | /:id? | {/:id}(可选组,? 后缀已不再支持) |
| 通配捕获 | * | *splat(命名)或 {*splat} |
| 参数内嵌正则 | /:id(\d+) | 不再支持,改用参数校验中间件或正则路由 |
// Express 4
app.get("/files/*", (req, res) => res.send(req.params[0]));
// Express 5(命名通配)
app.get("/files/*splat", (req, res) => res.send(req.params.splat));// Express 5 推荐:可选组 {/:page}
app.get("/books{/:page}", (req, res) => {
res.json({ page: req.params.page });
});res.sendfile / res.redirect 行为变化// Express 4 曾同时支持 sendfile(小写)
res.sendfile("data.txt");
// Express 5 统一为 sendFile(驼峰),并为流式错误改进了错误处理
res.sendFile(path.join(__dirname, "data.txt"));res.redirect("back")、res.redirect(301, url) 行为保持,但运行时抛出 ERR_HTTP_HEADERS_SENT 检查更严格。
# 升级主包
npm install express@5查看兼容中间件(大多数主流中间件已支持 5)。若个别中间件仍不兼容,先在隔离分支测试,或临时锁定其旧版本。
path-to-regexp@8 规则res.sendfile → res.sendFilenext(err) 包装(可选,保留也兼容)npm ls express 确认无依赖锁定在 4先用一条不影响主链路的服务验证 5 的行为,再逐模块切换;前端联调关注 404/路由通配后的路径形态。
新项目可直接:
npm install express@5并享受 async 自动错误处理带来的整洁代码。若团队里存在大量历史正则路由,则按需评估是否强制升级。
大概率是通配/正则语法差异。用上文「路径匹配语法变化」对照重写。
app.route().get(...) 吗?兼容,链式路由 (app.route) 与 express.Router 均在 5 中保留。
检查其 express 的 peerDependency;多数活跃中间件已发布 5 兼容版本。