十年前(2014年7月),Express v5 发布拉取请求 被提出,而现在它终于被合并并发布了!
🌐 Ten years ago (July 2014) the Express v5 release pull request was opened, and now at long last it’s been merged and published!
我们希望表彰所有贡献者的工作,特别是 Doug Wilson,他在过去十年中致力于确保 Express 成为最稳定的项目。没有他和许多其他人的贡献,这次发布是不可能实现的。
🌐 We want to recognize the work of all our contributors, especially Doug Wilson, who spent the last ten years ensuring Express was the most stable project around. Without his contributions and those of many others, this release could not have happened.
八个月前,我们公开了一个推动 Express 前进 的计划。该计划包括重新承诺多年前制定的治理方针,并增加更多贡献者以帮助启动进展。许多人可能没有意识到,强有力的项目治理对于大型开源项目的健康至关重要。我们要感谢 OpenJS 基金会跨项目委员会 及其成员帮助我们制定了这一计划。
🌐 Eight months ago we went public with a plan to move Express forward. This plan included re-committing to the governance outlined years ago and adding more contributors to help kickstart progress. Many people may not realize that robust project governance is critical to the health of a large open-source project. We want to thank the OpenJS Foundation Cross Project Council and its members for helping us put together this plan.
那 v5 呢?
🌐 So what about v5?
这个版本的发布本意是枯燥的! 这听起来可能很奇怪,但我们故意保持简单,以解除生态系统的阻碍,并在未来的版本中实现更有影响力的改变。这也意味着向 Node.js 生态系统传递一个信号,即 Express 正在重新前进。 本次发布的重点是放弃对旧版 Node.js 的支持,解决安全问题,以及简化维护工作。
🌐 This release is designed to be boring! That may sound odd, but we’ve intentionally kept it simple to unblock the ecosystem and enable more impactful changes in future releases. This is also about signaling to the Node.js ecosystem that Express is moving again. The focus of this release is on dropping old Node.js version support, addressing security concerns, and simplifying maintenance.
在介绍本次发布的变化之前,让我们先解释一下为什么它以 next dist-tag 发布为 v5。作为重振项目的一部分,我们启动了一个安全工作组和安全分诊团队,以应对日益增长的开源供应链安全需求。我们进行了一次安全审计(更多细节将随后发布),并发现了一些需要解决的问题。因此,除了在公开问题中完成的“正常”工作之外,我们还在私有分支中进行了大量的安全工作。
这项安全工作在发布时需要协调,以确保代码和 CVE 报告同时发布。你可以在我们的安全发布说明中找到最近修补的漏洞摘要。
🌐 Before going into the changes in this release, let’s address why it was released v5 on the next dist-tag. As part of reviving the project, we started a Security working group and security triage team to address the growing needs around open source supply chain security. We undertook a security audit (more details to come on that) and uncovered some problems that needed to be addressed. Thus, in addition to the “normal” work done in public issues, we also did a lot of security work in private forks.
This security work required orchestration when releasing, to ensure the code and CVE reports went out together. You can find a summary of the most recent vulnerabilities patched in our security release notes.
虽然我们无法同时发布 v5、这篇博客文章、更新日志和文档,但我们认为拥有一个安全稳定的版本最为重要。
🌐 While we weren’t able to simultaneously release v5, this blog post, the changelog, and documentation, we felt it was most important to have a secure and stable release.
我们将尽快提供关于长期支持(LTS)计划的更多细节,包括该版本何时会从 next 升级到 latest。目前,如果你对处于最新前沿不太放心(即使它相对平淡),那么你应该等待到该版本标记为 latest 再进行升级。话虽如此,我们期待与你合作,解决你在升级过程中遇到的任何错误。
🌐 As soon as possible, we’ll provide more details on our long-term support (LTS) plans, including when the release will move from next to latest. For now, if you are uncomfortable being on the bleeding edge (even if it is a rather dull edge) then you should wait to upgrade until the release is tagged latest. That said, we look forward to working with you to address any bugs you encounter as you upgrade.
重大变更
🌐 Breaking changes
v5 版本的发布包含尽可能少的破坏性更改,这些更改按对应用的影响顺序列出。
🌐 The v5 release has the minimum possible number of breaking changes, listed here in order of impact to applications.
还有一些细微的更改:详情请参见 迁移到 Express 5。
🌐 There are also a number of subtle changes: for details, see Migrating to Express 5.
结束对旧版 Node.js 的支持
🌐 Ending support for old Node.js versions
再见 Node.js 0.10,你好 Node 18 及以上版本!
🌐 Goodbye Node.js 0.10, hello Node 18 and up!
此版本不再支持 v18 之前的 Node.js 版本。这是一个重要的更改,因为支持旧的 Node.js 版本一直阻碍着许多关键的性能和可维护性改进。此更改还使持续集成(CI)更加稳定和可维护,采用新的语言和运行时特性,并移除不再需要的依赖。
🌐 This release drops support for Node.js versions before v18. This is an important change because supporting old Node.js versions has been holding back many critical performance and maintainability changes. This change also enables more stable and maintainable continuous integration (CI), adopting new language and runtime features, and dropping dependencies that are no longer required.
我们意识到这可能会给一些使用旧版或“搁置”应用的企业带来困难,因此我们正在与 HeroDevs 合作,提供“永不停歇的支持”,即使在 v4 进入生命周期结束后,也将包括关键的安全补丁(关于这些计划的更多信息将很快公布)。话虽如此,我们强烈建议你尽快升级到现代的 Node.js 版本。
🌐 We recognize that this might cause difficulty for some enterprises with older or “parked” applications, and because of this we are working on a partnership with HeroDevs to offer “never-ending support” that will include critical security patches even after v4 enters end-of-life (more on these plans soon). That said, we strongly suggest that you update to modern Node.js versions as soon as possible.
路径匹配和正则表达式的更改
🌐 Changes to path matching and regular expressions
v5 将 path-to-regexp@8.x 从 path-to-regexp@0.x 更新,这其中包含多年的更改。如果你使用的是任何 5.0.0-beta 版本,则有一个最后时刻的更新,它大幅改变了路径语义,以消除任何 ReDoS 攻击的可能性。有关更详细的更改,请参见 path-to-regexp 自述文件。
🌐 The v5 releases updates to path-to-regexp@8.x from path-to-regexp@0.x, which incorporates many years of changes. If you were using any of the 5.0.0-beta releases, a last-minute update which greatly changed the path semantics to remove the possibility of any ReDoS attacks. For more detailed changes, see the path-to-regexp readme.
不再使用正则表达式
🌐 No more regex
该版本不再支持“子表达式”正则表达式,例如“/:foo(\d+)”。 这是一个常用的模式,但出于安全原因我们已将其移除。不幸的是,很容易写出一个在解析输入时具有指数时间行为的正则表达式:令人畏惧的正则表达式拒绝服务攻击(ReDoS)。虽然很难防止这种情况,但作为一个将字符串转换为正则表达式的库,我们必须承担这些安全方面的责任。
🌐 This release no longer supports “sub-expression” regular expressions, for example /:foo(\\d+).
This is a commonly-used pattern, but we removed it for security reasons. Unfortunately, it’s easy to write a regular expression that has exponential time behavior when parsing input: The dreaded regular expression denial of service (ReDoS) attack. It’s very difficult to prevent this, but as a library that converts strings to regular expressions, we are on the hook for such security aspects.
如何迁移: 防止 ReDoS 攻击的最佳方法是使用强大的输入验证库。根据你的需求,npm 上有许多选择。TC 成员 Wes Todd 维护了一个基于中间件的“代码优先” OpenAPI 库来处理这类问题。
🌐 How to migrate: The best approach to prevent ReDoS attacks is to use a robust input validation library. There are many on npm depending on your needs. TC member Wes Todd maintains a middleware-based “code first” OpenAPI library for this kind of thing.
点状图,可选的,以及捕获,天哪
🌐 Splats, optional, and captures oh my
此版本包含适用于常见路由模式的简化模式。随着正则表达式语义的移除,编写路由的方式也会有其他一些小但有影响的变化。
🌐 This release includes simplified patterns for common route patterns. With the removal of regular expression semantics comes other small but impactful changes to how you write your routes.
:name?变为{:name}。在你的路由中使用{}表示可选部分,这意味着你现在可以做诸如/base{/:optional}/:required这样的操作,并且哪些部分实际上是可选的也变得更明确了。*变成*name。- 新的保留字符:
(、)、[、]、?、+和!。这些字符已被保留,以为未来的改进留出空间,并在迁移时防止因这些字符在先前版本中具有特定含义而导致的错误。
说出所有名字
🌐 Name everything
此版本不再支持有序的数值参数。
🌐 This release no longer supports ordered numerical parameters.
在 Express v4 中,你可以使用正则捕获组获取数字参数(例如,/user(s?) => req.params[0] === 's')。现在所有参数都必须有名称。除了需要名称之外,Express 现在还支持所有有效的 JavaScript 标识符或带引号的名称(例如,/:"this")。
🌐 In Express v4, you could get numerical parameters using regex capture groups (for example, /user(s?) => req.params[0] === 's'). Now all parameters must be named. Along with requiring a name, Express now supports all valid JavaScript identifiers or quoted (for example, /:"this").
承诺支持
🌐 Promise support
这一点可能有些有争议,但我们“保证”我们正在朝着正确的方向前进。我们增加了对从中间件中抛出的错误返回的 rejected Promise 的支持。这 不包括 从返回的 resolved Promise 调用 next。在旧的 Express 应用中有很多关于 Promise 行为的边缘情况,在我们能运行之前需要先逐步进行。对于大多数人来说,这意味着你现在可以像下面这样编写中间件:
🌐 This one may be a bit contentious, but we “promise” we’re moving in the right direction. We added support for returned rejected promises from errors raised in middleware. This does not include calling next from returned resolved promises. There are a lot of edge cases in old Express apps that have expectations of Promise behavior, and before we can run we need to walk. For most folks, this means you can now write middleware like the following:
app.use(async (req, res, next) => { req.locals.user = await getUser(req); next();});请注意,这个例子使用了 async/await,并且 getUser 调用可能会抛出错误(例如,如果用户不存在,用户数据库宕机等等),但是如果成功,我们仍然会调用 next。如果我们希望依赖错误处理中间件,就不再需要在本行捕获错误,因为路由现在会捕获被拒绝的承诺,并将其视为调用 next(err)。
🌐 Notice that this example uses async/await and the getUser call may throw an error (if, for example, the user doesn’t exist, the user database is down, and so on), but we still call next if it is successful. We don’t need to catch the error in line anymore if we want to rely on error-handling middleware instead because the router will now catch the rejected promise and treat that as calling next(err).
注意:最佳做法是尽可能在错误发生的地方处理错误。所以虽然现在是在路由中处理,但最好是在中间件中捕获错误并进行处理,而不依赖于单独的错误处理中间件。
🌐 NOTE: Best practice is to handle errors as close to the site as possible. So while this is now handled in the router, it’s best to catch the error in the middleware and handle it without relying on separate error-handling middleware.
Body parser 更改
🌐 Body parser changes
有一些 body-parser 变更:
🌐 There are a number of body-parser changes:
- 添加选项以自定义 urlencoded 正文的深度,默认值为 32,以缓解 CVE-2024-45590 (技术细节)
- 移除已弃用的
bodyParser()组合中间件 req.body不再总是初始化为{}urlencoded解析器现在默认将extended设置为 false- 新增对Brotli无损数据压缩的支持
移除已弃用的方法签名
🌐 Removing deprecated method signatures
Express v5 移除了许多已弃用的方法签名,其中许多方法是从 v3 延续过来的。下面是你需要做的更改:
🌐 Express v5 removes a number of deprecated method signatures, many of which were carried over from v3. Below are the changes you need to make:
res.redirect('back')和res.location('back'):魔术字符串'back'不再受支持。请改为显式使用req.get('Referrer') || '/'。res.send(status, body)和res.send(body, status)签名:使用res.status(status).send(body)。res.send(status)签名:使用res.sendStatus(status)进行简单状态响应,或使用res.status(status).send()发送带可选正文的状态码。res.redirect(url, status)签名:使用res.redirect(status, url)。res.json(status, obj)和res.json(obj, status)签名:使用res.status(status).json(obj)。res.jsonp(status, obj)和res.jsonp(obj, status)签名:使用res.status(status).jsonp(obj)。app.param(fn):此方法已被弃用。请改为通过req.params直接访问参数,或根据需要使用req.body或req.query。app.del('/', () => {})方法:请改用app.delete('/', () => {})。req.acceptsCharset:使用req.acceptsCharsets(复数)。req.acceptsEncoding:使用req.acceptsEncodings(复数)。req.acceptsLanguage:使用req.acceptsLanguages(复数)。res.sendfile方法:请改用res.sendFile。
作为一个框架,我们的目标是确保 API 尽可能一致。我们已经移除了这些已废弃的签名,以使 API 更可预测且更易于使用。通过将每个方法简化为使用单一、统一的签名,我们简化了开发者的体验并减少了混淆。
🌐 As a framework, we aim to ensure that the API is as consistent as possible. We’ve removed these deprecated signatures to make the API more predictable and easier to use. By streamlining each method to use a single, consistent signature, we simplify the developer experience and reduce confusion.
迁移与安全指南
🌐 Migration and security guidance
对于希望从 v4 迁移到 v5 的开发者,有一份详细的迁移指南可以帮助你了解变化并确保升级过程顺利。
🌐 For developers looking to migrate from v4 to v5, there’s a detailed migration guide to help you navigate through the changes and ensure a smooth upgrade process.
此外,我们一直在努力制定一个全面的威胁模型,以帮助说明我们关于“快速、无偏见、极简的 Node.js Web 框架”的理念。它提供了关键的见解,涵盖例如用户输入验证和安全实践等字段,这些都是在应用中安全使用 Express 所必需的。
🌐 Additionally, we’ve been working hard on a comprehensive Threat Model that helps illustrate our philosophy of a “Fast, unopinionated, minimalist web framework for Node.js.” It provides critical insights into areas like user input validation and security practices that are essential for safe and secure usage of Express in your applications.
我们的工作才刚刚开始
🌐 Our work is just starting
我们将 v5 版本视为朝着一个稳定可靠的 Express 生态系统迈出的里程碑,该生态系统将成为企业、政府、教育工作者和业余项目的有力工具。作为 Express 项目的新管理者,我们承诺以这一目标推动生态系统的发展。如果你希望支持这项工作,而我们是以志愿者方式进行的,请考虑通过我们的赞助机会支持该项目及其维护者。
🌐 We see the v5 release as a milestone toward an Express ecosystem that’s a stable and reliable tool for companies, governments, educators, and hobby projects. It is our commitment as the new stewards of the Express project to move the ecosystem forward with this goal in mind. If you want to support this work, which we do on a volunteer basis, please consider supporting the project and its maintainers via our sponsorship opportunities.
我们有一个大量未完成的工作积压,包括 Express 和其依赖的任务、PR 和问题。自然地,我们预计开发者将继续报告问题以增加这个积压,并在未来提交更多的 PR,我们也将继续与社区合作,对这些问题进行分类和解决。我们期待继续改进 Express,并使其对全球用户更有用。
🌐 We have an extensive working backlog of tasks, PRs, and issues for Express and dependencies. Naturally, we expect developers will continue to report issues to add to this backlog and open PRs moving forward, and we’ll continue to collaborate with the community to triage and resolve them. We look forward to continuing to improve Express and making it useful for its users across the world.



