🌐 Nodejs.cn

升级到 Express v5

Express 5 与 Express 4 没有太大区别;尽管它保持了相同的基本 API,但仍然有一些更改会破坏与前一个版本的兼容性。因此,用 Express 4 构建的应用在更新到使用 Express 5 时可能无法正常工作。

🌐 Express 5 is not very different from Express 4; although it maintains the same basic API, there are still changes that break compatibility with the previous version. Therefore, an application built with Express 4 might not work if you update it to use Express 5.

安装

🌐 Installation

要安装此版本,你需要拥有 Node.js 18 或更高版本。然后,在你的应用目录中执行以下命令:

🌐 To install this version, you need to have a Node.js version 18 or higher. Then, execute the following command in your application directory:

Terminal window
npm install "express@5"

然后你可以运行自动化测试以查看哪些测试失败,并根据下面列出的更新修复问题。解决测试失败后,运行你的应用以查看会出现哪些错误。你会立即发现应用是否使用了任何不受支持的方法或属性。

🌐 You can then run your automated tests to see what fails, and fix problems according to the updates listed below. After addressing test failures, run your app to see what errors occur. You’ll find out right away if the app uses any methods or properties that are not supported.

Express 5 代码修改工具

🌐 Express 5 Codemods

为了帮助你迁移你的 Express 服务器,我们创建了一套代码转换工具,帮助你自动将代码更新到最新版本的 Express。

🌐 To help you migrate your express server, we have created a set of codemods that will help you automatically update your code to the latest version of Express.

运行以下命令以运行所有可用的代码转换工具:

🌐 Run the following command for run all the codemods available:

Terminal window
npx codemod@latest @expressjs/v5-migration-recipe

如果你想运行特定的代码修改器,你可以运行以下命令:

🌐 If you want to run a specific codemod, you can run the following command:

Terminal window
npx codemod@latest @expressjs/name-of-the-codemod

你可以在此处找到可用的代码修改列表。

🌐 You can find the list of available codemods here.

已移除的方法和属性

🌐 Removed methods and properties

如果你在应用中使用这些方法或属性,应用将会崩溃。因此,在更新到版本5之后,你需要更改你的应用。

🌐 If you use any of these methods or properties in your app, it will crash. So, you’ll need to change your app after you update to version 5.

app.del()

Express 5 不再支持 app.del() 函数。如果使用此函数,将会抛出错误。要注册 HTTP DELETE 路由,请改用 app.delete() 函数。

🌐 Express 5 no longer supports the app.del() function. If you use this function, an error is thrown. For registering HTTP DELETE routes, use the app.delete() function instead.

最初,使用 del 而不是 delete,因为 delete 是 JavaScript 中的保留关键字。然而,从 ECMAScript 6 开始,delete 和其他保留关键字可以合法地用作属性名。

🌐 Initially, del was used instead of delete, because delete is a reserved keyword in JavaScript. However, as of ECMAScript 6, delete and other reserved keywords can legally be used as property names.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/route-del-to-delete

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.del('/user/:id', (req, res) => {
app.delete('/user/:id', (req, res) => {
res.send(`DELETE /user/${req.params.id}`);
});

app.param(fn)

app.param(fn) 签名曾用于修改 app.param(name, fn) 函数的行为。自 v4.11.0 起,它已被弃用,并且 Express 5 已完全不再支持它。

🌐 The app.param(fn) signature was used for modifying the behavior of the app.param(name, fn) function. It has been deprecated since v4.11.0, and Express 5 no longer supports it at all.

复数形式的方法名

🌐 Pluralized method names

以下方法名称已被复数化。在 Express 4 中,使用旧方法会导致弃用警告。Express 5 已完全不再支持这些方法:

🌐 The following method names have been pluralized. In Express 4, using the old methods resulted in a deprecation warning. Express 5 no longer supports them at all:

req.acceptsCharset()req.acceptsCharsets() 替换。

req.acceptsEncoding()req.acceptsEncodings() 替换。

req.acceptsLanguage()req.acceptsLanguages() 替换。

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/pluralize-method-names

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.all('/', (req, res) => {
req.acceptsCharset('utf-8');
req.acceptsEncoding('br');
req.acceptsLanguage('en');
req.acceptsCharsets('utf-8');
req.acceptsEncodings('br');
req.acceptsLanguages('en');
// ...
});

在 app.param(name, fn) 的名称中以冒号 (:) 开头

🌐 Leading colon (:) in the name for app.param(name, fn)

app.param(name, fn) 函数名称中的前导冒号 (:) 是 Express 3 的遗留部分,为了向后兼容,Express 4 支持它并会显示弃用通知。Express 5 将会静默忽略它,并使用不带冒号前缀的名称参数。

🌐 A leading colon character (:) in the name for the app.param(name, fn) function is a remnant of Express 3, and for the sake of backwards compatibility, Express 4 supported it with a deprecation notice. Express 5 will silently ignore it and use the name parameter without prefixing it with a colon.

如果你遵循 Express 4 文档中关于 app.param 的说明,这不应该影响你的代码,因为文档中没有提到前导冒号。

🌐 This should not affect your code if you follow the Express 4 documentation of app.param, as it makes no mention of the leading colon.

req.param(name)

这种可能引起混淆和危险的获取表单数据的方法已被移除。你现在需要在 req.paramsreq.bodyreq.query 对象中专门查找提交的参数名称。

🌐 This potentially confusing and dangerous method of retrieving form data has been removed. You will now need to specifically look for the submitted parameter name in the req.params, req.body, or req.query object.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/explicit-request-params

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.post('/user', (req, res) => {
const id = req.param('id');
const body = req.param('body');
const query = req.param('query');
const id = req.params.id;
const body = req.body;
const query = req.query;
// ...
});

res.json(obj, 状态)

🌐 res.json(obj, status)

Express 5 不再支持签名 res.json(obj, status)。相反,请先设置状态,然后将其链式调用到 res.json() 方法,如下所示:res.status(status).json(obj)

🌐 Express 5 no longer supports the signature res.json(obj, status). Instead, set the status and then chain it to the res.json() method like this: res.status(status).json(obj).

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/status-send-order

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.post('/user', (req, res) => {
res.json({ name: 'Ruben' }, 201);
res.status(201).json({ name: 'Ruben' });
});

res.jsonp(obj, status)

Express 5 不再支持签名 res.jsonp(obj, status)。相反,请先设置状态,然后将其链式调用到 res.jsonp() 方法,如下所示:res.status(status).jsonp(obj)

🌐 Express 5 no longer supports the signature res.jsonp(obj, status). Instead, set the status and then chain it to the res.jsonp() method like this: res.status(status).jsonp(obj).

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/status-send-order

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.post('/user', (req, res) => {
res.jsonp({ name: 'Ruben' }, 201);
res.status(201).jsonp({ name: 'Ruben' });
});

res.redirect(url, 状态)

🌐 res.redirect(url, status)

Express 5 不再支持签名 res.redirect(url, status)。请改用以下签名:res.redirect(status, url)

🌐 Express 5 no longer supports the signature res.redirect(url, status). Instead, use the following signature: res.redirect(status, url).

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/redirect-arg-order

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.get('/user', (req, res) => {
res.redirect('/users', 302);
res.redirect(302, '/users');
});
// A redirect that relies on the default 302 status is unaffected
app.get('/admin', (req, res) => {
res.redirect('/dashboard');
});

res.redirect(‘back’) 和 res.location(‘back’)

🌐 res.redirect(‘back’) and res.location(‘back’)

Express 5 不再在 res.redirect()res.location() 方法中支持魔法字符串 back。取而代之的是,使用 req.get('Referrer') || '/' 值重定向回上一页。在 Express 4 中,res.redirect('back')res.location('back') 方法已被弃用。

🌐 Express 5 no longer supports the magic string back in the res.redirect() and res.location() methods. Instead, use the req.get('Referrer') || '/' value to redirect back to the previous page. In Express 4, the res.redirect('back') and res.location('back') methods were deprecated.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/back-redirect-deprecated

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.get('/user', (req, res) => {
res.redirect('back');
res.redirect(req.get('Referrer') || '/');
});

res.send(body, status)

Express 5 不再支持签名 res.send(obj, status)。相反,请先设置状态,然后将其链式调用到 res.send() 方法,如下所示:res.status(status).send(obj)

🌐 Express 5 no longer supports the signature res.send(obj, status). Instead, set the status and then chain it to the res.send() method like this: res.status(status).send(obj).

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/status-send-order

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.get('/user', (req, res) => {
res.send({ name: 'Ruben' }, 200);
res.status(200).send({ name: 'Ruben' });
});

res.send(status)

Express 5 不再支持签名 res.send(status),其中 status 是一个数字。取而代之,请使用 res.sendStatus(statusCode) 函数,该函数设置 HTTP 响应头的状态码并发送状态码的文本版本,例如:“Not Found”、“Internal Server Error”等。如果你需要使用 res.send() 函数发送数字,请将数字加上引号以转换为字符串,这样 Express 就不会将其解释为尝试使用不受支持的旧签名。

🌐 Express 5 no longer supports the signature res.send(status), where status is a number. Instead, use the res.sendStatus(statusCode) function, which sets the HTTP response header status code and sends the text version of the code: “Not Found”, “Internal Server Error”, and so on. If you need to send a number by using the res.send() function, quote the number to convert it to a string, so that Express does not interpret it as an attempt to use the unsupported old signature.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/status-send-order

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.get('/user', (req, res) => {
res.send(200);
res.sendStatus(200);
});

res.sendfile()

res.sendfile() 函数已在 Express 5 中被驼峰式命名的版本 res.sendFile() 取代。

🌐 The res.sendfile() function has been replaced by a camel-cased version res.sendFile() in Express 5.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/camelcase-sendfile

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.get('/user', (req, res) => {
res.sendfile('/path/to/file');
res.sendFile('/path/to/file');
});

res.sendFile() 选项

🌐 res.sendFile() options

res.sendFile()hiddenfrom 选项不再受支持。请改用 dotfilesroot

🌐 The hidden and from options for res.sendFile() are no longer supported. Use dotfiles and root instead.

dotfiles 选项适用于路径中的隐藏目录以及隐藏文件。例如,从像 /var/www/app/.cache/index.html 这样的绝对路径提供的文件现在需要 dotfiles: 'allow',即使 index.html 不是点文件。在 Express 4 中,路径中的隐藏目录默认是可以访问的;Express 5 除非你选择启用,否则会返回 404

🌐 The dotfiles option applies to hidden directories in the path as well as hidden files. For example, a file served from an absolute path like /var/www/app/.cache/index.html now requires dotfiles: 'allow', even though index.html is not a dotfile. In Express 4 a hidden directory in the path was served by default; Express 5 returns 404 unless you opt in.

此检查仅适用于 send 评估的路径部分。当你传递一个 root 时,只检查与 root 相关的部分,因此 root 内的隐藏目录不受影响。

🌐 This check only applies to the part of the path that send evaluates. When you pass a root, only the portion relative to root is checked, so a hidden directory inside root is unaffected.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/sendfile-options

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

app.get('/files/:name', (req, res) => {
res.sendFile(req.params.name, { hidden: true, from: '/uploads' });
res.sendFile(req.params.name, { dotfiles: 'allow', root: '/uploads' });
});

如果你提供一个包含隐藏目录的绝对路径,请选择使用 dotfiles: 'allow' 或使用 root,以便隐藏部分不会成为评估路径的一部分:

🌐 If you serve an absolute path that contains a hidden directory, opt in with dotfiles: 'allow' or use root so the hidden segment is not part of the evaluated path:

app.get('/build', (req, res) => {
res.sendFile('/var/www/app/.cache/index.html');
res.sendFile('/var/www/app/.cache/index.html', { dotfiles: 'allow' });
// or: res.sendFile('index.html', { root: '/var/www/app/.cache' });
});

express.static() 选项

🌐 express.static() options

express.static()hiddenfrom 选项不再受支持。请改用 dotfilesroot。请注意,from 从未在 API 中记录,但被接受作为 root 的别名。dotfiles 的默认值现在是 "ignore"

🌐 The hidden and from options for express.static() are no longer supported. Use dotfiles and root instead. Note that from was never documented in the API but was accepted as an alias for root. The default value of dotfiles is now "ignore".

dotfiles 检查现在也适用于请求路径中的隐藏目录,而不仅仅是隐藏文件。像 GET /.well-known/acme-challenge/... 这样的请求,在 Express 4 中默认被处理,现在会返回 404,除非你设置了 dotfiles: 'allow'。这只影响相对于配置的 root 的路径部分;root 本身的隐藏目录不受影响。

🌐 The dotfiles check now also applies to hidden directories in the request path, not just hidden files. A request like GET /.well-known/acme-challenge/... that was served by default in Express 4 now returns 404 unless you set dotfiles: 'allow'. This only affects the part of the path relative to the configured root; a hidden directory in root itself is unaffected.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/static-dotfiles

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

const express = require('express');
const app = express();
app.use(express.static('public', { hidden: true }));
app.use(express.static('public', { dotfiles: 'allow' }));

如果你依赖于提供一个隐藏目录,例如 .well-known(例如,ACME/Let’s Encrypt 挑战),请明确选择使用。即使你从未使用过 hidden 选项,也需要这样做:

🌐 If you rely on serving a hidden directory such as .well-known (for example, ACME/Let’s Encrypt challenges), opt in explicitly. This is needed even if you never used the hidden option:

app.use(express.static('public'));
app.use(express.static('public', { dotfiles: 'allow' }));

router.param(fn)

router.param(fn) 签名曾用于修改 router.param(name, fn) 函数的行为。自 v4.11.0 起,它已被弃用,并且 Express 5 已完全不再支持它。

🌐 The router.param(fn) signature was used for modifying the behavior of the router.param(name, fn) function. It has been deprecated since v4.11.0, and Express 5 no longer supports it at all.

express.static.mime

在 Express 5 中,mime 不再是 static 字段的导出属性。使用 mime-types 来处理 MIME 类型值。

🌐 In Express 5, mime is no longer an exported property of the static field. Use the mime-types package to work with MIME type values.

如何更新

🌐 How to update

你可以通过运行以下命令自动更新你的代码:

🌐 You can automatically update your code by running the following command:

Terminal window
npx codemod@latest @expressjs/static-mime

或者你可以手动更新你的代码:

🌐 Or you can update your code manually:

express.static.mime.lookup('json');
const mime = require('mime-types');
mime.lookup('json');

MIME 类型更改

🌐 MIME type changes

由于 mime-db 的更新,多个 MIME 类型已发生变化。这些更改仅影响 express.static()res.sendFile()。有关完整的更改列表,请参阅 mime-db 更新日志

🌐 Several MIME types have changed due to updates in mime-db. These changes only affect express.static() and res.sendFile(). For a full list of changes, see the mime-db changelog.

Express 4 使用 mime-db 版本 1.52.0,而 Express 5 使用反映 IANA 和其他 MIME 类型规范更新的较新版本。最显著的变化是 JavaScript 文件(.js)现在作为 text/javascript 而不是 application/javascript 提供。

🌐 Express 4 uses mime-db version 1.52.0, while Express 5 uses newer versions that reflect updates to IANA and other MIME type specifications. The most notable change is that JavaScript files (.js) are now served as text/javascript instead of application/javascript.

在 Express 5 中,来自 mime-db 更新的 MIME 类型更改不被认为是破坏性更改,因此在更新依赖时要小心,因为 MIME 类型可能在次要版本或补丁版本之间发生变化。

🌐 In Express 5, changes to MIME types from mime-db updates are not considered breaking changes, so be careful when updating your dependencies as MIME types may change between minor or patch versions.

express:router 调试日志

🌐 express:router debug logs

路由处理逻辑现在由 Express 团队维护的一个独立依赖 (router) 执行,因此调试日志已移至不同的命名空间。在 Express 5.1 之前,这些调试日志不存在。要获取它们,请更新到最新的 Express 5 版本或更新你在 package-lock.json 中的 router 包:

🌐 Router handling logic is now performed by a separate dependency (router) maintained by the Express team, so debug logs have moved to a different namespace. Before Express 5.1, these debug logs did not exist. To get them, update to a recent Express 5 version or update the router package in your package-lock.json:

v4v5
express:routerrouter
express:router:layerrouter:layer
express:router:routerouter:route
express:*(包括全部)express:* + router + router:*

如何更新

🌐 How to update

DEBUG=express:* node index.js
DEBUG=express:*,router,router:* node index.js

已更改

🌐 Changed

这些 API 仍然存在,但它们的行为已经发生了变化。请检查这些变化以确保你的应用按预期工作。

🌐 These APIs still exist but their behavior has changed. Review these changes to make sure your app works as expected.

路径路由匹配语法

🌐 Path route matching syntax

路径路由匹配语法是指当字符串作为第一个参数提供给 app.all()app.use()app.METHOD()router.all()router.METHOD()router.use() API 时。针对路径字符串与传入请求匹配的方式已进行了以下更改:

🌐 Path route matching syntax is when a string is supplied as the first parameter to the app.all(), app.use(), app.METHOD(), router.all(), router.METHOD(), and router.use() APIs. The following changes have been made to how the path string is matched to an incoming request:

  • 通配符 * 必须有一个名称,以匹配参数 : 的行为,使用 /*splat 替代 /*

    app.get('/*', async (req, res) => {
    app.get('/*splat', async (req, res) => {
    res.send('ok');
    });

Note

*splat 匹配任何没有根路径的路径。如果你也需要匹配根路径 /,你可以使用 /{*splat},将通配符封装在大括号中。

app.get('/{*splat}', async (req, res) => {
res.send('ok');
});
  • 可选字符 ? 不再受支持,请改用大括号。

    app.get('/:file.:ext?', async (req, res) => {
    app.get('/:file{.:ext}', async (req, res) => {
    res.send('ok');
    });
  • 不支持正则表达式字符。例如:

    app.get('/[discussion|page]/:slug', async (req, res) => {
    app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => {
    res.status(200).send('ok');
    });
  • 有些字符已被保留以避免升级期间的混淆(()[]?+!),使用 \ 来转义它们。

  • 参数名称现在支持有效的 JavaScript 标识符,或者像 :"this" 这样加引号。

从中间件和处理程序处理的被拒绝的承诺

🌐 Rejected promises handled from middleware and handlers

返回被拒绝的 Promise 的请求中间件和处理程序现在会通过将被拒绝的值作为 Error 转发到错误处理中间件来处理。这意味着将 async 函数用作中间件和处理程序比以往任何时候都更容易。当在 async 函数中抛出错误或在异步函数中 await 一个被拒绝的 Promise 时,这些错误将像调用 next(err) 一样传递给错误处理程序。

🌐 Request middleware and handlers that return rejected promises are now handled by forwarding the rejected value as an Error to the error handling middleware. This means that using async functions as middleware and handlers are easier than ever. When an error is thrown in an async function or a rejected promise is awaited inside an async function, those errors will be passed to the error handler as if calling next(err).

Express 如何处理错误的详细信息在错误处理文档中有所说明。

🌐 Details of how Express handles errors is covered in the error handling documentation.

如何更新

🌐 How to update

你现在可以直接使用 async/await 而无需手动捕获错误。如果 getUserById 抛出错误或拒绝,next 将会自动使用被拒绝的值被调用。

🌐 You can now use async/await directly without manually catching errors. If getUserById throws an error or rejects, next will be called automatically with the rejected value.

app.get('/user/:id', (req, res, next) => {
getUserById(req.params.id)
.then((user) => res.send(user))
.catch(next);
});
app.get('/user/:id', async (req, res) => {
const user = await getUserById(req.params.id);
res.send(user);
});

express.urlencoded

express.urlencoded 方法默认使 extended 选项为 false

🌐 The express.urlencoded method makes the extended option false by default.

如何更新

🌐 How to update

如果你的应用依赖于 extended 行为,请将其显式设置为 true

🌐 If your application relies on the extended behavior, explicitly set it to true:

app.use(express.urlencoded());
app.use(express.urlencoded({ extended: true }));

express.static dotfiles

express.static 中间件的 dotfiles 选项现在默认值为 "ignore"。在 Express 4 中,点文件默认是可以被访问的。因此,位于以点开头的目录(.)中的文件,例如 .well-known,将不再可访问,并会返回 404 Not Found 错误。这可能会破坏依赖于提供点目录的功能,例如 Android 应用链接和 Apple 通用链接。

🌐 The express.static middleware’s dotfiles option now defaults to "ignore". In Express 4, dotfiles were served by default. As a result, files inside a directory that starts with a dot (.), such as .well-known, will no longer be accessible and will return a 404 Not Found error. This can break functionality that depends on serving dot-directories, such as Android App Links and Apple Universal Links.

如何更新

🌐 How to update

使用 dotfiles: "allow" 选项明确提供特定的点目录。这允许你安全地仅提供预期的点目录,同时保持其他点文件的默认安全行为。

🌐 Serve specific dot-directories explicitly using the dotfiles: "allow" option. This allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles.

app.use('/.well-known', express.static('public/.well-known', { dotfiles: 'allow' }));
app.use(express.static('public'));

router.param() 与一个名称数组

🌐 router.param() with an array of names

router.param(name, fn) 不再接受 name 的数组。在 Express 4 中,数组会被静默接受;在 Express 5 中,传入非字符串的值会抛出 TypeError: argument name must be a string。(注意,app.param() 仍然接受名称数组。)

如何更新

🌐 How to update

使用各自的 router.param() 调用注册每个参数名称:

🌐 Register each parameter name with its own router.param() call:

router.param(['id', 'page'], (req, res, next, value) => {
// ...
});
const loadParam = (req, res, next, value) => {
// ...
};
router.param('id', loadParam);
router.param('page', loadParam);

app.listen

在 Express 5 中,当服务器收到错误事件时,app.listen 方法会调用用户提供的回调函数(如果提供)。在 Express 4 中,这类错误会被抛出。此更改将错误处理的责任转移到 Express 5 中的回调函数。如果发生错误,它将作为参数传递给回调函数。 例如:

🌐 In Express 5, the app.listen method will invoke the user-provided callback function (if provided) when the server receives an error event. In Express 4, such errors would be thrown. This change shifts error-handling responsibility to the callback function in Express 5. If there is an error, it will be passed to the callback as an argument. For example:

const server = app.listen(8080, '0.0.0.0', (error) => {
if (error) {
throw error; // e.g. EADDRINUSE
}
console.log(`Listening on ${JSON.stringify(server.address())}`);
});

app.router

app.router 对象在 Express 4 中被移除,但在 Express 5 中又回来了。在新版本中,这个对象只是对基础 Express 路由的一个引用,不像在 Express 3 中,应用必须显式加载它。

🌐 The app.router object, which was removed in Express 4, has made a comeback in Express 5. In the new version, this object is a just a reference to the base Express router, unlike in Express 3, where an app had to explicitly load it.

req.body

req.body 属性在正文未解析时返回 undefined。在 Express 4 中,它默认返回 {}

🌐 The req.body property returns undefined when the body has not been parsed. In Express 4, it returns {} by default.

app.post('/user', (req, res) => {
console.dir(req.body);
// Express 4
// => {}
// Express 5
// => undefined
});

req.host

在 Express 4 中,如果存在端口号,req.host 函数会错误地去掉端口号。在 Express 5 中,端口号得以保留。

🌐 In Express 4, the req.host function incorrectly stripped off the port number if it was present. In Express 5, the port number is maintained.

req.params

req.params 对象在使用字符串路径时现在具有 空原型。然而,如果路径是使用正则表达式定义的,req.params 仍然是具有正常原型的标准对象。此外,还有两个重要的行为变化:

🌐 The req.params object now has a null prototype when using string paths. However, if the path is defined with a regular expression, req.params remains a standard object with a normal prototype. Additionally, there are two important behavioral changes:

通配符参数现在是数组:

通配符(例如,/*splat)将路径段捕获为数组,而不是单个字符串。

🌐 Wildcards (e.g., /*splat) capture path segments as an array instead of a single string.

app.get('/*splat', (req, res) => {
// GET /foo/bar
console.dir(req.params);
// => [Object: null prototype] { splat: [ 'foo', 'bar' ] }
});

未匹配的参数将被省略:

在 Express 4 中,不匹配的通配符是空字符串(''),可选的 : 参数(使用 ?)有一个键,其值为 undefined。在 Express 5 中,不匹配的参数将从 req.params 中完全省略。

🌐 In Express 4, unmatched wildcards were empty strings ('') and optional : parameters (using ?) had a key with value undefined. In Express 5, unmatched parameters are completely omitted from req.params.

// v4: unmatched wildcard is empty string
app.get('/*', (req, res) => {
// GET /
console.dir(req.params);
// => { '0': '' }
});
// v4: unmatched optional param is undefined
app.get('/:file.:ext?', (req, res) => {
// GET /image
console.dir(req.params);
// => { file: 'image', ext: undefined }
});
// v5: unmatched optional param is omitted
app.get('/:file{.:ext}', (req, res) => {
// GET /image
console.dir(req.params);
// => [Object: null prototype] { file: 'image' }
});

req.query

req.query 属性不再是可写属性,而是一个 getter。默认的查询解析器已从 “extended” 更改为 “simple”。

🌐 The req.query property is no longer a writable property and is instead a getter. The default query parser has been changed from “extended” to “simple”.

app.get('/search', (req, res) => {
// This is no longer possible in Express 5
req.query.page = 1;
});

res.clearCookie

res.clearCookie 方法会忽略用户提供的 maxAgeexpires 选项。

🌐 The res.clearCookie method ignores the maxAge and expires options provided by the user.

app.get('/logout', (req, res) => {
res.clearCookie('session', { maxAge: 0, expires: new Date(0) });
res.clearCookie('session');
});

res.status

res.status 方法只接受范围在 100999 之间的整数,按照 Node.js 定义的行为,当状态码不是整数时,它会返回错误。

🌐 The res.status method only accepts integers in the range of 100 to 999, following the behavior defined by Node.js, and it returns an error when the status code is not an integer.

app.get('/user', (req, res) => {
res.status(99); // Throws an error
res.status(200); // OK
});

res.vary

res.vary 在缺少 field 参数时会抛出错误。在 Express 4 中,如果省略了该参数,会在控制台给出警告。

🌐 The res.vary throws an error when the field argument is missing. In Express 4, if the argument was omitted, it gave a warning in the console.

app.get('/user', (req, res) => {
res.vary(); // Throws an error
res.vary('Accept'); // OK
});

改进

🌐 Improvements

这些更改不需要任何迁移步骤,但在升级时值得了解。

🌐 These changes don’t require any migration steps, but are worth knowing about when upgrading.

res.render()

该方法现在对所有视图引擎强制执行异步行为,从而避免了那些具有同步实现并且违反推荐接口的视图引擎引起的错误。

🌐 This method now enforces asynchronous behavior for all view engines, avoiding bugs caused by view engines that had a synchronous implementation and that violated the recommended interface.

Brotli 编码支持

🌐 Brotli encoding support

express.json()express.urlencoded()express.text()express.raw() 这样的中间件现在支持使用 Brotli (Content-Encoding: br) 对传入请求体进行解压缩,除此之外还支持 gzipdeflate

🌐 Middleware like express.json(), express.urlencoded(), express.text(), and express.raw() now support Brotli (Content-Encoding: br) decompression for incoming request bodies, in addition to gzip and deflate.