迁移到 Express 5
概述
Express 5 与 Express 4 没有太大区别;尽管它保持了相同的基本 API,但仍然存在一些不兼容先前版本的更改。因此,使用 Express 4 构建的应用程序,在更新到 Express 5 后可能无法正常工作。
要安装此版本,您需要 Node.js 18 或更高版本。然后,在您的应用程序目录中执行以下命令
npm install "express@5"
然后,您可以运行自动化测试以查看哪些失败,并根据下面列出的更新修复问题。解决测试失败后,运行您的应用程序以查看发生哪些错误。您将立即发现应用程序是否使用了任何不受支持的方法或属性。
Express 5 Codemods
为了帮助您迁移 Express 服务器,我们创建了一套 codemods,可以帮助您自动将代码更新到最新版本的 Express。
运行以下命令以运行所有可用的 codemods
npx @expressjs/codemod upgrade
如果您想运行特定的 codemod,可以运行以下命令
npx @expressjs/codemod name-of-the-codemod
您可以在此处找到可用 codemods 的列表。
Express 5 中的变更
已移除的方法和属性
- app.del()
- app.param(fn)
- 方法名称复数化
- app.param(name, fn) 中 name 参数的前导冒号
- req.param(name)
- res.json(obj, status)
- res.jsonp(obj, status)
- res.redirect('back') 和 res.location('back')
- res.redirect(url, status)
- res.send(body, status)
- res.send(status)
- res.sendfile()
- router.param(fn)
- express.static.mime
- express:router 调试日志
已更改
- 路径路由匹配语法
- 中间件和处理程序处理被拒绝的 Promise
- express.urlencoded
- app.listen
- app.router
- req.body
- req.host
- req.query
- res.clearCookie
- res.status
- res.vary
改进
已移除的方法和属性
如果您的应用程序使用了这些方法或属性中的任何一个,它将会崩溃。因此,在更新到版本 5 后,您需要更改您的应用程序。
app.del()
Express 5 不再支持 app.del()
函数。如果您使用此函数,将抛出错误。要注册 HTTP DELETE 路由,请改用 app.delete()
函数。
最初,使用 del
而不是 delete
,因为 delete
是 JavaScript 中的保留关键字。然而,从 ECMAScript 6 开始,delete
和其他保留关键字可以合法地用作属性名。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// 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}`)
})
app.param(fn)
app.param(fn)
签名用于修改 app.param(name, fn)
函数的行为。它自 v4.11.0 起已弃用,Express 5 完全不再支持它。
方法名称复数化
以下方法名称已复数化。在 Express 4 中,使用旧方法会发出弃用警告。Express 5 完全不再支持它们
req.acceptsCharset()
已被 req.acceptsCharsets()
替换。
req.acceptsEncoding()
已被 req.acceptsEncodings()
替换。
req.acceptsLanguage()
已被 req.acceptsLanguages()
替换。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod pluralized-methods
// 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')
// ...
})
app.param(name, fn) 中 name 的前导冒号 (:)
app.param(name, fn)
函数中 name 参数的前导冒号字符 (:) 是 Express 3 的遗留问题,为了向后兼容,Express 4 支持它并带有弃用通知。Express 5 将默默地忽略它,并使用不带冒号前缀的 name 参数。
如果您遵循 app.param 的 Express 4 文档,这不应该影响您的代码,因为它没有提及前导冒号。
req.param(name)
这种可能令人困惑且危险的检索表单数据的方法已被移除。您现在需要特意在 req.params
、req.body
或 req.query
对象中查找提交的参数名。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod req-param
// 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
// ...
})
res.json(obj, status)
Express 5 不再支持 res.json(obj, status)
签名。相反,请先设置状态,然后将其链接到 res.json()
方法,例如:res.status(status).json(obj)
。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// v4
app.post('/user', (req, res) => {
res.json({ name: 'Ruben' }, 201)
})
// v5
app.post('/user', (req, res) => {
res.status(201).json({ name: 'Ruben' })
})
res.jsonp(obj, status)
Express 5 不再支持 res.jsonp(obj, status)
签名。相反,请先设置状态,然后将其链接到 res.jsonp()
方法,例如:res.status(status).jsonp(obj)
。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// v4
app.post('/user', (req, res) => {
res.jsonp({ name: 'Ruben' }, 201)
})
// v5
app.post('/user', (req, res) => {
res.status(201).jsonp({ name: 'Ruben' })
})
res.redirect(url, status)
Express 5 不再支持 res.redirect(url, status)
签名。请改用以下签名:res.redirect(status, url)
。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// v4
app.get('/user', (req, res) => {
res.redirect('/users', 301)
})
// v5
app.get('/user', (req, res) => {
res.redirect(301, '/users')
})
res.redirect('back') 和 res.location('back')
Express 5 不再支持 res.redirect()
和 res.location()
方法中的魔术字符串 back
。请改用 req.get('Referrer') || '/'
值来重定向回上一页。在 Express 4 中,res.redirect('back')
和 res.location('back')
方法已弃用。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod magic-redirect
// v4
app.get('/user', (req, res) => {
res.redirect('back')
})
// v5
app.get('/user', (req, res) => {
res.redirect(req.get('Referrer') || '/')
})
res.send(body, status)
Express 5 不再支持 res.send(obj, status)
签名。相反,请先设置状态,然后将其链接到 res.send()
方法,例如:res.status(status).send(obj)
。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// v4
app.get('/user', (req, res) => {
res.send({ name: 'Ruben' }, 200)
})
// v5
app.get('/user', (req, res) => {
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 就不会将其解释为尝试使用不受支持的旧签名。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// v4
app.get('/user', (req, res) => {
res.send(200)
})
// v5
app.get('/user', (req, res) => {
res.sendStatus(200)
})
res.sendfile()
res.sendfile()
函数在 Express 5 中已被驼峰命名法版本 res.sendFile()
替换。
注意
您可以使用以下命令替换已弃用的签名
npx @expressjs/codemod v4-deprecated-signatures
// v4
app.get('/user', (req, res) => {
res.sendfile('/path/to/file')
})
// v5
app.get('/user', (req, res) => {
res.sendFile('/path/to/file')
})
router.param(fn)
router.param(fn)
签名用于修改 router.param(name, fn)
函数的行为。它自 v4.11.0 起已弃用,Express 5 完全不再支持它。
express.static.mime
在 Express 5 中,mime
不再是 static
字段的导出属性。请使用 mime-types
包来处理 MIME 类型值。
// v4
express.static.mime.lookup('json')
// v5
const mime = require('mime-types')
mime.lookup('json')
express:router 调试日志
在 Express 5 中,路由器处理逻辑由一个依赖项执行。因此,路由器的调试日志不再在 express:
命名空间下可用。在 v4 中,日志在 express:router
、express:router:layer
和 express:router:route
命名空间下可用。所有这些都包含在 express:*
命名空间下。在 v5.1+ 中,日志在 router
、router:layer
和 router:route
命名空间下可用。router:layer
和 router:route
的日志包含在 router:*
命名空间中。为了在使用 v4 中的 express:*
时获得相同的详细调试日志,请结合使用 express:*
、router
和 router:*
。
# v4
DEBUG=express:* node index.js
# v5
DEBUG=express:*,router,router:* node index.js
已更改
路径路由匹配语法
路径路由匹配语法是指将字符串作为第一个参数提供给 app.all()
、app.use()
、app.METHOD()
、router.all()
、router.METHOD()
和 router.use()
API。对路径字符串如何与传入请求匹配进行了以下更改
- 通配符
*
必须有一个名称,与参数:
的行为匹配,使用/*splat
而不是/*
// v4
app.get('/*', async (req, res) => {
res.send('ok')
})
// v5
app.get('/*splat', async (req, res) => {
res.send('ok')
})
注意
*splat
匹配不带根路径的任何路径。如果您还需要匹配根路径 /
,可以使用 /{*splat}
,将通配符括在花括号中。
// v5
app.get('/{*splat}', async (req, res) => {
res.send('ok')
})
- 不再支持可选字符
?
,请改用花括号。
// v4
app.get('/:file.:ext?', async (req, res) => {
res.send('ok')
})
// v5
app.get('/:file{.:ext}', async (req, res) => {
res.send('ok')
})
- 不支持正则表达式字符。例如
app.get('/[discussion|page]/:slug', async (req, res) => { res.status(200).send('ok') })
应更改为
app.get(['/discussion/:slug', '/page/:slug'], async (req, res) => { res.status(200).send('ok') })
- 某些字符已被保留以避免升级过程中混淆 (
()[]?+!
),请使用\
进行转义。 - 参数名现在支持有效的 JavaScript 标识符,或用引号括起来,如
:"this"
。
中间件和处理程序处理被拒绝的 Promise
返回被拒绝 Promise 的请求中间件和处理程序现在通过将被拒绝的值作为 Error
转发给错误处理中间件来处理。这意味着将 async
函数用作中间件和处理程序比以往任何时候都更容易。当在 async
函数中抛出错误或在 async 函数内部 await
被拒绝的 Promise 时,这些错误将传递给错误处理程序,就像调用 next(err)
一样。
Express 如何处理错误的详细信息,请参阅错误处理文档。
express.urlencoded
express.urlencoded
方法默认将 extended
选项设为 false
。
app.listen
在 Express 5 中,当服务器收到错误事件时,app.listen
方法将调用用户提供的回调函数(如果提供)。在 Express 4 中,此类错误将被抛出。此更改将错误处理职责转移到 Express 5 中的回调函数。如果出现错误,它将作为参数传递给回调。例如
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
在 Express 4 中被移除的 app.router
对象在 Express 5 中卷土重来。在新版本中,此对象只是对基础 Express 路由器的引用,与 Express 3 不同,Express 3 中应用程序必须显式加载它。
req.body
当请求体未被解析时,req.body
属性返回 undefined
。在 Express 4 中,它默认返回 {}
。
req.host
在 Express 4 中,req.host
函数错误地去掉了存在的端口号。在 Express 5 中,端口号得以保留。
req.query
req.query
属性不再是可写属性,而是一个 getter。默认的查询解析器已从“extended”更改为“simple”。
res.clearCookie
res.clearCookie
方法忽略用户提供的 maxAge
和 expires
选项。
res.status
res.status
方法只接受 100
到 999
范围内的整数,遵循 Node.js 定义的行为,并且当状态码不是整数时会返回错误。
res.vary
当缺少 field
参数时,res.vary
会抛出错误。在 Express 4 中,如果省略该参数,则会在控制台中给出警告
改进
res.render()
此方法现在强制所有视图引擎采用异步行为,从而避免了由于视图引擎的同步实现而导致的错误,这些实现违反了推荐的接口。
Brotli 编码支持
Express 5 支持 Brotli 编码,用于处理支持它的客户端发出的请求。
编辑此页面