Express 5 升级要注意的几个变化
Express 5 在拖了将近十年之后终于正式发布。大部分 API 保持不变,但有几处改动会让老代码直接报错。下面是我升级几个项目时遇到的问题。
1. 异步错误终于能自动捕获了
这是最值得升级的理由。Express 4 中,async 函数里抛出的异常不会进入错误处理中间件,要么自己 try/catch,要么装 express-async-errors。
Express 5 中,路由处理函数返回的 Promise 被 reject 时,会自动调用 next(err):
app.get('/user/:id', async (req, res) => {
const user = await db.getUser(req.params.id); // 抛错会自动进入错误处理中间件
res.json(user);
});
升级后可以删掉 express-async-errors 这类补丁。
2. 路由路径语法变了
Express 5 使用新版的 path-to-regexp,有几个写法不再支持:
// 通配符必须命名
app.get('/*', handler); // Express 4
app.get('/*splat', handler); // Express 5
// 可选参数改用花括号
app.get('/user/:id?', handler); // Express 4
app.get('/user{/:id}', handler); // Express 5
字符串路径里也不能再写正则字符(如 (、)、+),需要正则时直接传 RegExp 对象。
3. req.body 默认是 undefined
在 Express 5 中,如果请求体没有被任何解析中间件处理(比如 GET 请求,或 Content-Type 不匹配),req.body 是 undefined,而不是空对象。
const { name } = req.body; // 可能直接报错
可以加一个兜底中间件,或者在使用处写成 req.body ?? {}。
4. urlencoded 的 extended 默认为 false
express.urlencoded() 不传参数时,默认使用简单的解析方式,a[b]=1 不会再被解析成嵌套对象。需要嵌套结构的话要显式指定 extended: true。
5. req.query 变成了只读
req.query 现在是一个 getter,不能直接赋值修改。一些"在中间件里清洗 query 参数再写回去"的写法会失效,需要改成把结果放到别的属性上,比如 req.validatedQuery。
6. 删除的 API
| 已删除 | 替代 |
|---|---|
app.del() |
app.delete() |
res.redirect('back') |
res.redirect(req.get('Referrer') || '/') |
res.send(200) |
res.sendStatus(200) |
res.json(obj, 200) |
res.status(200).json(obj) |
req.param('name') |
req.params / req.body / req.query |
7. 最低需要 Node.js 18
如果服务器上的 Node 版本还很老,先升级 Node。
升级建议
- 全局搜索
'*'、:\w+?这类路由写法,按新语法修改; - 搜索
req.body的解构,确认有兜底; - 跑一遍完整的测试或手动点一遍主要流程;
- 删掉不再需要的异步错误补丁。
对于中小项目,整个升级通常一两个小时就能完成。