---
layout: page
title: 迁移到 Express 5
description: A comprehensive guide to migrating your Express.js applications from version 4 to 5, detailing breaking changes, deprecated methods, and new improvements.
menu: guide
order: 10
redirect_from: "  "
---

# 迁移到 Express 5

<h2 id="overview">概述</h2>

Express 5 与 Express 4 的差异不是很大：对 API 的更改不像 3.0 到 4.0 升级那样大刀阔斧。虽然基本 API 保持相同，但仍有一些重大更改；换言之，如果将现有 Express 4 程序更新为使用 Express 5，那么该程序可能无法工作。 Therefore, an application built with Express 4 might not work if you update it to use Express 5.

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

```sh
npm install "express@5"
```

随后，可以运行自动化测试以查看哪些地方发生故障，然后根据以下列出的更新修复问题。在解决测试故障问题之后，运行应用程序以查看发生哪些错误。如果应用程序使用任何不受支持的方法或属性，您马上就可以发现。 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 Codemods

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:

```sh
npx @expressjs/codemod upgrade
```

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

```sh
npx @expressjs/codemod name-of-the-codemod
```

You can find the list of available codemods [here](https://github.com/expressjs/codemod?tab=readme-ov-file#available-codemods).

<h2 id="changes">Express 5 中的更改</h2>

**已移除的方法和属性**

<ul class="doclist">
  <li><a href="#app.del">app.del()</a></li>
  <li><a href="#app.param">app.param(fn)</a></li>
  <li><a href="#plural">复数的方法名称</a></li>
  <li><a href="#leading">app.param(name, fn) 的 name 自变量中的前置冒号</a></li>
  <li><a href="#req.param">req.param(name)</a></li>
  <li><a href="#res.json">res.json(obj, status)</a></li>
  <li><a href="#res.jsonp">res.jsonp(obj, status)</a></li>
  <li><a href="#magic-redirect">res.redirect('back') and res.location('back')</a></li>
  <li><a href="#res.redirect">res.redirect(url, status)</a></li>
  <li><a href="#res.send.body">res.send(body, status)</a></li>
  <li><a href="#res.send.status">res.send(status)</a></li>
  <li><a href="#res.sendfile">res.sendfile()</a></li>
  <li><a href="#router.param">router.param(fn)</a></li>
  <li><a href="#express.static.mime">express.static.mime</a></li>
  <li><a href="#express:router-debug-logs">express:router debug logs</a></li>
</ul>

**改进**

<ul class="doclist">
  <li><a href="#path-syntax">Path route matching syntax</a></li>
  <li><a href="#rejected-promises">Rejected promises handled from middleware and handlers</a></li>
  <li><a href="#express.urlencoded">express.urlencoded</a></li>
  <li><a href="#express.static.dotfiles">express.static dotfiles</a></li>
  <li><a href="#app.listen">app.listen</a></li>
  <li><a href="#app.router">app.router</a></li>
  <li><a href="#req.body">req.body</a></li>
  <li><a href="#req.host">req.host</a></li>
  <li><a href="#req.params">req.params</a></li>
  <li><a href="#req.query">req.query</a></li>
  <li><a href="#res.clearCookie">res.clearCookie</a></li>
  <li><a href="#res.status">res.status</a></li>
  <li><a href="#res.vary">res.vary</a></li>
</ul>

**已更改**

<ul class="doclist">
  <li><a href="#res.render">res.render()</a></li>
  <li><a href="#brotli-support">Brotli encoding support</a></li>
</ul>

## 已移除的方法和属性

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.

<h3 id="app.del">app.del()</h3>

Express 5 不再支持 `app.del()` 函数。如果使用此函数，将抛出错误。要注册 HTTP DELETE 路由，请使用 `app.delete()` 函数。 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` 和其他保留关键字可以合法地用作属性名称。您可以在此阅读该讨论，这导致我们在此不推荐使用 `app.del` 函数。 However, as of ECMAScript 6, `delete` and other reserved keywords can legally be used as property names.

{% capture codemod-deprecated-signatures %}
You can replace the deprecated signatures with the following command:

```plaintext
npx @expressjs/codemod v4-deprecated-signatures
```

{% endcapture %}

{% include admonitions/note.html content=codemod-deprecated-signatures %}

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

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

<h3 id="app.param">app.param(fn)</h3>

`app.param(fn)` 特征符用于修改 `app.param(name, fn)` 函数的行为。自 V4.11.0 起不推荐使用该特征符，而 Express 5 完全不再提供支持。 It has been deprecated since v4.11.0, and Express 5 no longer supports it at all.

<h3 id="plural">复数的方法名称</h3>

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.acceptsLanguage()` 由 `req.acceptsLanguages()` 取代。

`req.acceptsCharset()` 由 `req.acceptsCharsets()` 取代。

`req.acceptsEncoding()` 由 `req.acceptsEncodings()` 取代。

{% capture codemod-pluralized-methods %}
You can replace the deprecated signatures with the following command:

```plaintext
npx @expressjs/codemod pluralized-methods
```

{% endcapture %}

{% include admonitions/note.html content=codemod-pluralized-methods %}

```js
// v4
app.all("/", (req, res) => {
  req.acceptsCharset("utf-8");
  req.acceptsEncoding("br");
  req.acceptsLanguage("en");

  // ...
});

// v5
app.all("/", (req, res) => {
  req.acceptsCharsets("utf-8");
  req.acceptsEncodings("br");
  req.acceptsLanguages("en");

  // ...
});
```

<h3 id="leading">app.param(name, fn) 的名称中的前置冒号 (:)</h3>

`app.param(name, fn)` 函数名称中的前置冒号字符 (:) 是 Express 3 的遗留问题，为了向后兼容性，Express 4 提供支持但会显示不推荐使用的提醒。而 Express 5 则静默忽略它，使用不带前置冒号的名称参数。 Express 5 will silently ignore it and use the name parameter without prefixing it with a colon.

如果您遵循 [app.param](/{{ page.lang }}/4x/api.html#app.param) 的 Express 4 文档进行开发，那么不会影响代码，因为文档中没有提及前置冒号。

<h3 id="req.param">req.param(name)</h3>

This potentially confusing and dangerous method of retrieving form data has been removed. 已移除用于检索表单数据的方法，因为这可能引起混淆，而且很危险。现在，您需要在 `req.params`、`req.body` 或 `req.query` 对象中专门寻找提交的参数名称。

{% capture codemod-req-param %}
You can replace the deprecated signatures with the following command:

```plaintext
npx @expressjs/codemod req-param
```

{% endcapture %}

{% include admonitions/note.html content=codemod-req-param %}

```js
// v4
app.post("/user", (req, res) => {
  const id = req.param("id");
  const body = req.param("body");
  const query = req.param("query");

  // ...
});

// v5
app.post("/user", (req, res) => {
  const id = req.params.id;
  const body = req.body;
  const query = req.query;

  // ...
});
```

<h3 id="res.json">res.json(obj, status)</h3>

Express 5 不再支持特征符 `res.json(obj, status)`。而是设置状态，然后将其链接到 `res.json()` 方法，如下所示：`res.status(status).json(obj)`。 Instead, set the status and then chain it to the `res.json()` method like this: `res.status(status).json(obj)`.

{% include admonitions/note.html content=codemod-deprecated-signatures %}

```js
// v4
app.post("/user", (req, res) => {
  res.json({ name: "Ruben" }, 201);
});

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

<h3 id="res.jsonp">res.jsonp(obj, status)</h3>

Express 5 不再支持特征符 `res.jsonp(obj, status)`。而是设置状态，然后将其链接到 `res.jsonp()` 方法，如下所示：`res.status(status).jsonp(obj)`。 Instead, set the status and then chain it to the `res.jsonp()` method like this: `res.status(status).jsonp(obj)`.

{% include admonitions/note.html content=codemod-deprecated-signatures %}

```js
// v4
app.post("/user", (req, res) => {
  res.jsonp({ name: "Ruben" }, 201);
});

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

<h3 id="res.redirect">res.redirect(url, status)</h3>

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

{% include admonitions/note.html content=codemod-deprecated-signatures %}

```js
// v4
app.get("/user", (req, res) => {
  res.redirect("/users", 301);
});

// v5
app.get("/user", (req, res) => {
  res.redirect(301, "/users");
});
```

<h3 id="magic-redirect">res.redirect('back') and res.location('back')</h3>

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.

{% capture codemod-magic-redirect %}
You can replace the deprecated signatures with the following command:

```plaintext
npx @expressjs/codemod magic-redirect
```

{% endcapture %}

{% include admonitions/note.html content=codemod-magic-redirect %}

```js
// v4
app.get("/user", (req, res) => {
  res.redirect("back");
});

// v5
app.get("/user", (req, res) => {
  res.redirect(req.get("Referrer") || "/");
});
```

<h3 id="res.send.body">res.send(body, status)</h3>

Express 5 不再支持特征符 `res.send(obj, status)`。而是设置状态，然后将其链接到 `res.send()` 方法，如下所示：`res.status(status).send(obj)`。 Instead, set the status and then chain it to the `res.send()` method like this: `res.status(status).send(obj)`.

{% include admonitions/note.html content=codemod-deprecated-signatures %}

```js
// v4
app.get("/user", (req, res) => {
  res.send({ name: "Ruben" }, 200);
});

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

<h3 id="res.send.status">res.send(status)</h3>

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.

{% include admonitions/note.html content=codemod-deprecated-signatures %}

```js
// v4
app.get("/user", (req, res) => {
  res.send(200);
});

// v5
app.get("/user", (req, res) => {
  res.sendStatus(200);
});
```

<h3 id="res.sendfile">res.sendfile()</h3>

在 Express 5 中，`res.sendfile()` 函数已由驼峰式大小写版本 `res.sendFile()` 替换。

**Note:** In Express 5, `res.sendFile()` uses the `mime-types` package for MIME type detection, which returns different Content-Type values than Express 4 for several common file types:

- JavaScript files (.js): now "text/javascript" instead of "application/javascript"
- JSON files (.json): now "application/json" instead of "text/json"
- CSS files (.css): now "text/css" instead of "text/plain"
- XML files (.xml): now "application/xml" instead of "text/xml"
- Font files (.woff): now "font/woff" instead of "application/font-woff"
- SVG files (.svg): now "image/svg+xml" instead of "application/svg+xml"

{% include admonitions/note.html content=codemod-deprecated-signatures %}

```js
// v4
app.get("/user", (req, res) => {
  res.sendfile("/path/to/file");
});

// v5
app.get("/user", (req, res) => {
  res.sendFile("/path/to/file");
});
```

<h3 id="router.param">router.param(fn)</h3>

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.

<h3 id="express.static.mime">express.static.mime</h3>

In Express 5, `mime` is no longer an exported property of the `static` field.
Use the [`mime-types` package](https://github.com/jshttp/mime-types) to work with MIME type values.

**Important:** This change affects not only direct usage of `express.static.mime` but also other Express methods that rely on MIME type detection, such as `res.sendFile()`. The following MIME types have changed from Express 4:

- JavaScript files (.js): now served as "text/javascript" instead of "application/javascript"
- JSON files (.json): now served as "application/json" instead of "text/json"
- CSS files (.css): now served as "text/css" instead of "text/plain"
- HTML files (.html): now served as "text/html; charset=utf-8" instead of just "text/html"
- XML files (.xml): now served as "application/xml" instead of "text/xml"
- Font files (.woff): now served as "font/woff" instead of "application/font-woff"

```js
// v4
express.static.mime.lookup("json");

// v5
const mime = require("mime-types");
mime.lookup("json");
```

<h3 id="express:router-debug-logs">express:router debug logs</h3>

In Express 5, router handling logic is performed by a dependency. Therefore, the
debug logs for the router are no longer available under the `express:` namespace.
In v4, the logs were available under the namespaces `express:router`, `express:router:layer`,
and `express:router:route`. All of these were included under the namespace `express:*`.
In v5.1+, the logs are available under the namespaces `router`, `router:layer`, and `router:route`.
The logs from `router:layer` and `router:route` are included in the namespace `router:*`.
To achieve the same detail of debug logging when using `express:*` in v4, use a conjunction of
`express:*`, `router`, and `router:*`.

```sh
# v4
DEBUG=express:* node index.js

# v5
DEBUG=express:*,router,router:* node index.js
```

## 已更改

<h3 id="path-syntax">Path route matching syntax</h3>

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:

- The wildcard `*` must have a name, matching the behavior of parameters `:`, use `/*splat` instead of `/*`

```js
// v4
app.get("/*", async (req, res) => {
  res.send("ok");
});

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

{% capture note_wildcard %}
`*splat` matches any path without the root path. If you need to match the root path as well `/`, you can use `/{*splat}`, wrapping the wildcard in braces.

```js
// v5
app.get("/{*splat}", async (req, res) => {
  res.send("ok");
});
```

{% endcapture %}
{% include admonitions/note.html content=note_wildcard %}

- The optional character `?` is no longer supported, use braces instead.

```js
// v4
app.get("/:file.:ext?", async (req, res) => {
  res.send("ok");
});

// v5
app.get("/:file{.:ext}", async (req, res) => {
  res.send("ok");
});
```

- Regexp characters are not supported. For example:

```js
app.get("/[discussion|page]/:slug", async (req, res) => {
  res.status(200).send("ok");
});
```

should be changed to:

```js
app.get(["/discussion/:slug", "/page/:slug"], async (req, res) => {
  res.status(200).send("ok");
});
```

- Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`), use `\` to escape them.
- Parameter names now support valid JavaScript identifiers, or quoted like `:"this"`.

<h3 id="rejected-promises">Rejected promises handled from middleware and handlers</h3>

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 `await`ed inside an async function, those errors will be passed to the error handler as if calling `next(err)`.

Details of how Express handles errors is covered in the [error handling documentation](/en/guide/error-handling.html).

<h3 id="express.urlencoded">express.urlencoded</h3>

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

<h3 id="express.static.dotfiles">express.static dotfiles</h3>

In Express 5, the `express.static` middleware's `dotfiles` option now defaults to `"ignore"`. This is a change from Express 4, where 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.

Example of breaking code:

```js
// v4
app.use(express.static("public"));
```

After migrating to Express 5, a request to `/.well-known/assetlinks.json` will result in a **404 Not Found**.

To fix this, serve specific dot-directories explicitly using the `dotfiles: "allow"` option:

```js
// v5
app.use(
  "/.well-known",
  express.static("public/.well-known", { dotfiles: "allow" }),
);
app.use(express.static("public"));
```

This approach allows you to safely serve only the intended dot-directories while keeping the default secure behavior for other dotfiles, which remain inaccessible.

<h3 id="app.listen">app.listen</h3>

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:

```js
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())}`);
});
```

<h3 id="app.router">app.router</h3>

在 Express 4 中已移除的 `app.router` 对象在 Express 5 中已恢复。在新版本中，此对象只是对 Express 基本路由器的引用，不像在 Express 3 中应用程序必须显式将该路由器装入。 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.

<h3 id="req.body">req.body</h3>

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

<h3 id="req.host">req.host</h3>

在 Express 4 中，如果存在端口号，`req.host` 函数会错误地将其剥离。在 Express 5 中，则会保留端口号。 In Express 5, the port number is maintained.

<h3 id="req.params">req.params</h3>

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:

**Wildcard parameters are now arrays:**

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

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

**Unmatched parameters are omitted:**

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`.

```js
// 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' }
});
```

<h3 id="req.query">req.query</h3>

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".

<h3 id="res.clearCookie">res.clearCookie</h3>

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

<h3 id="res.status">res.status</h3>

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.

<h3 id="res.query">res.vary</h3>

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

## 改进

<h3 id="res.render">res.render()</h3>

现在，此方法为所有查看引擎强制执行异步行为，避免具有同步实现以及违反建议接口的查看引擎所导致的错误。

<h3 id="brotli-support">Brotli encoding support</h3>

Express 5 supports Brotli encoding for requests received from clients that support it.
