介绍 Express v5:Node.js 框架的新时代

2024 年 10 月 15 日

十年前(2014 年 7 月),Express v5 发布拉取请求被打开,现在终于被合并并发布了!

我们感谢所有贡献者的工作,特别是 Doug Wilson,他过去十年一直致力于确保 Express 是最稳定的项目。没有他以及许多其他人的贡献,这次发布就不可能实现。

八个月前,我们公开了一项计划,旨在推动 Express 发展。该计划包括重新承诺多年前概述的治理,并增加更多贡献者来启动进展。许多人可能没有意识到,健全的项目治理对于一个大型开源项目的健康至关重要。我们感谢 OpenJS 基金会跨项目委员会及其成员帮助我们制定了这项计划。

那么 v5 呢?

这次发布旨在“无聊”!这听起来可能很奇怪,但我们有意保持简单,以解除生态系统的阻塞,并为未来版本中更具影响力的变化提供可能。这也在向 Node.js 生态系统发出信号,表明 Express 正在重新行动起来。本次发布的重点是停止对旧 Node.js 版本的支持,解决安全问题,并简化维护。

在深入探讨本次发布中的变化之前,我们先解释一下为什么它是在 next dist-tag 上发布 v5 的。作为项目复兴的一部分,我们成立了一个安全工作组安全分类团队,以应对开源供应链安全日益增长的需求。我们进行了一次安全审计(更多细节即将公布),发现了一些需要解决的问题。因此,除了在公共问题中进行的“正常”工作之外,我们还在私人分支中进行了大量的安全工作。这项安全工作在发布时需要协调,以确保代码和 CVE 报告同时发布。您可以在我们的安全发布说明中找到最新修补漏洞的摘要。

虽然我们未能同时发布 v5、这篇博客文章、更新日志和文档,但我们认为拥有一个安全稳定的发布最为重要。

我们将尽快提供有关我们的长期支持 (LTS) 计划的更多详细信息,包括何时将版本从 next 移动到 latest。目前,如果您不习惯使用最前沿的版本(即使它相当稳定),那么您应该等到版本被标记为 latest 后再升级。尽管如此,我们期待与您合作,解决您在升级过程中遇到的任何错误。

突破性变更

v5 版本具有最少量的突破性变更,按对应用程序的影响程度在此处列出。

还有一些细微的变化:有关详细信息,请参阅迁移到 Express 5

终止对旧 Node.js 版本的支持

再见 Node.js 0.10,你好 Node 18 及更高版本!

此版本取消了对 v18 之前 Node.js 版本的支持。这是一个重要的变化,因为支持旧的 Node.js 版本一直阻碍着许多关键的性能和可维护性改进。此更改还支持更稳定和可维护的持续集成 (CI),采用新的语言和运行时特性,并取消不再需要的依赖项。

我们认识到这可能会给一些拥有旧的或“停滞”应用程序的企业带来困难,因此我们正在与 HeroDevs 合作,提供“永续支持”,即使在 v4 终止生命周期后,仍将包括关键安全补丁(有关这些计划的更多信息即将发布)。尽管如此,我们强烈建议您尽快更新到现代 Node.js 版本。

路径匹配和正则表达式的更改

v5 版本将 [email protected] 更新为 [email protected],其中包含了多年的变化。如果您曾使用任何 5.0.0-beta 版本,请注意最后一刻的更新,该更新极大地改变了路径语义,以消除任何 ReDoS 攻击的可能性。有关更详细的更改,请参阅 path-to-regexp 的 README

不再支持正则表达式

此版本不再支持“子表达式”正则表达式,例如 /:foo(\\d+)。这是一个常用的模式,但我们出于安全原因将其移除。不幸的是,很容易编写出在解析输入时具有指数时间行为的正则表达式:即可怕的正则表达式拒绝服务 (ReDoS) 攻击。这很难预防,但作为一个将字符串转换为正则表达式的库,我们有责任处理这些安全方面的问题。

如何迁移:防止 ReDoS 攻击的最佳方法是使用健壮的输入验证库。npm 上有许多,具体取决于您的需求。TC 成员 Wes Todd 维护着一个基于中间件的“代码优先”OpenAPI 库,用于处理此类问题。

通配符、可选参数和捕获

此版本包含了对常见路由模式的简化模式。随着正则表达式语义的移除,您的路由编写方式也发生了一些细微但有影响的更改。

  1. :name? 变为 {:name}。在路由的可选部分使用 {} 意味着您现在可以执行 /base{/:optional}/:required 之类的操作,并且哪些部分是可选的也更加明确。
  2. * 变为 *name
  3. 新的保留字符:()[]?+!。这些字符已被保留,以便为未来的改进留出空间,并防止在迁移时出现错误,因为这些字符在以前的版本中具有特定含义。

命名所有参数

此版本不再支持有序数字参数。

在 Express v4 中,您可以使用正则表达式捕获组获取数字参数(例如,/user(s?) => req.params[0] === 's')。现在所有参数都必须命名。除了要求命名外,Express 现在支持所有有效的 JavaScript 标识符或带引号的标识符(例如,/:"this")。

Promise 支持

这一点可能有点争议,但我们“保证”我们正朝着正确的方向前进。我们增加了对中间件中引发的错误返回被拒绝的 Promise 的支持。这不包括从返回的已解决的 Promise 中调用 next。旧的 Express 应用程序中存在许多对 Promise 行为有预期的边缘情况,在我们能够奔跑之前,我们需要先学会走路。对于大多数人来说,这意味着您现在可以编写如下所示的中间件:

app.use(async (req, res, next) => {
  req.locals.user = await getUser(req);
  next();
});

请注意,此示例使用 async/await,并且 getUser 调用可能会抛出错误(例如,用户不存在,用户数据库宕机等),但如果成功,我们仍然会调用 next。如果我们要依赖错误处理中间件,我们不再需要在线捕获错误,因为路由器现在将捕获被拒绝的 Promise,并将其视为调用 next(err)

注意:最佳实践是在尽可能靠近发生错误的地方处理错误。因此,虽然现在在路由器中处理,但最好在中间件中捕获错误并进行处理,而无需依赖单独的错误处理中间件。

Body parser 变更

body-parser 有一些变化:

移除已弃用的方法签名

Express v5 移除了许多已弃用的方法签名,其中许多是从 v3 继承下来的。以下是您需要进行的更改:

作为一个框架,我们的目标是确保 API 尽可能保持一致。我们已移除这些已弃用的签名,以使 API 更具可预测性且更易于使用。通过简化每个方法以使用单一、一致的签名,我们简化了开发人员的体验并减少了混淆。

迁移和安全指南

对于希望从 v4 迁移到 v5 的开发人员,我们提供了详细的迁移指南,以帮助您了解这些变化并确保顺利升级。

此外,我们一直致力于制定全面的威胁模型,以阐明我们“快速、不固执己见、极简的 Node.js Web 框架”的理念。它提供了关于用户输入验证和安全实践等关键领域的见解,这些对于在应用程序中安全使用 Express 至关重要。

我们的工作才刚刚开始

我们认为 v5 版本的发布是 Express 生态系统朝着为公司、政府、教育者和业余项目提供稳定可靠工具迈出的里程碑。作为 Express 项目的新管理者,我们承诺秉持这一目标推动生态系统向前发展。如果您希望支持我们这项志愿工作,请考虑通过我们的赞助机会支持该项目及其维护者。

我们有一个庞大的待办任务、拉取请求和 Express 及其依赖项问题列表。自然,我们希望开发人员将继续报告问题以补充此待办事项,并提出新的拉取请求,我们将继续与社区合作,对它们进行分类和解决。我们期待继续改进 Express,使其对全球用户有用。

编辑此页面