5.x API
express()
创建一个 Express 应用程序。 express()
函数是 express
模块导出的一个顶级函数。
const express = require('express')
const app = express()
方法
express.json([options])
这是 Express 中一个内置的中间件函数。它解析带有 JSON 有效负载的传入请求,并基于 body-parser。
返回一个中间件,该中间件只解析 JSON,并且只处理 Content-Type
头与 type
选项匹配的请求。此解析器接受主体的任何 Unicode 编码,并支持 gzip
和 deflate
编码的自动解压缩。
在中间件之后,包含已解析数据的新 body
对象会填充到 request
对象上(即 req.body
),如果没有要解析的主体、Content-Type
不匹配或发生错误,则为 undefined
。
由于 req.body
的结构基于用户控制的输入,因此此对象中的所有属性和值均不可信,在使用前应进行验证。例如,req.body.foo.toString()
可能会以多种方式失败,例如 foo
可能不存在或不是字符串,并且 toString
可能不是函数,而是字符串或其他用户输入。
下表描述了可选 options
对象的属性。
属性 | 描述 | 类型 | 默认值 |
---|---|---|---|
inflate |
启用或禁用处理解压缩(压缩)的主体;禁用时,解压缩的主体将被拒绝。 | 布尔值 | true |
limit |
控制最大请求主体大小。如果是数字,则值指定字节数;如果是字符串,则值传递给 bytes 库进行解析。 | 混合 | "100kb" |
reviver |
reviver 选项直接作为第二个参数传递给 JSON.parse 。您可以在 MDN 关于 JSON.parse 的文档中找到有关此参数的更多信息。 |
函数 | null |
strict |
启用或禁用只接受数组和对象;禁用时将接受 JSON.parse 接受的任何内容。 |
布尔值 | true |
type |
这用于确定中间件将解析的媒体类型。此选项可以是字符串、字符串数组或函数。如果不是函数,type 选项直接传递给 type-is 库,这可以是扩展名(如 json )、MIME 类型(如 application/json ),或带有通配符的 MIME 类型(如 */* 或 */json )。如果是函数,type 选项将作为 fn(req) 调用,如果它返回一个真值,则解析请求。 |
混合 | "application/json" |
verify |
如果提供此选项,它将作为 verify(req, res, buf, encoding) 调用,其中 buf 是原始请求主体的 Buffer ,encoding 是请求的编码。解析可以通过抛出错误来中止。 |
函数 | undefined |
express.raw([options])
这是 Express 中一个内置的中间件函数。它将传入的请求有效负载解析为 Buffer
,并基于 body-parser。
返回一个中间件,该中间件将所有主体解析为 Buffer
,并且只处理 Content-Type
头与 type
选项匹配的请求。此解析器接受主体的任何 Unicode 编码,并支持 gzip
和 deflate
编码的自动解压缩。
在中间件之后,包含已解析数据的新 body
Buffer
会填充到 request
对象上(即 req.body
),如果没有要解析的主体、Content-Type
不匹配或发生错误,则为 undefined
。
由于 req.body
的结构基于用户控制的输入,因此此对象中的所有属性和值均不可信,在使用前应进行验证。例如,req.body.toString()
可能会以多种方式失败,例如堆叠多个解析器时,req.body
可能来自不同的解析器。建议在调用缓冲区方法之前测试 req.body
是否为 Buffer
。
下表描述了可选 options
对象的属性。
属性 | 描述 | 类型 | 默认值 |
---|---|---|---|
inflate |
启用或禁用处理解压缩(压缩)的主体;禁用时,解压缩的主体将被拒绝。 | 布尔值 | true |
limit |
控制最大请求主体大小。如果是数字,则值指定字节数;如果是字符串,则值传递给 bytes 库进行解析。 | 混合 | "100kb" |
type |
这用于确定中间件将解析的媒体类型。此选项可以是字符串、字符串数组或函数。如果不是函数,type 选项直接传递给 type-is 库,这可以是扩展名(如 bin )、MIME 类型(如 application/octet-stream ),或带有通配符的 MIME 类型(如 */* 或 application/* )。如果是函数,type 选项将作为 fn(req) 调用,如果它返回一个真值,则解析请求。 |
混合 | "application/octet-stream" |
verify |
如果提供此选项,它将作为 verify(req, res, buf, encoding) 调用,其中 buf 是原始请求主体的 Buffer ,encoding 是请求的编码。解析可以通过抛出错误来中止。 |
函数 | undefined |
express.Router([options])
创建一个新的路由对象。
const router = express.Router([options])
可选的 options
参数指定路由器的行为。
属性 | 描述 | 默认值 | 可用性 |
---|---|---|---|
caseSensitive |
启用大小写敏感。 | 默认禁用,将“/Foo”和“/foo”视为相同。 | |
mergeParams |
保留父路由器的 req.params 值。如果父级和子级具有冲突的参数名称,则子级的值优先。 |
false |
4.5.0+ |
strict |
启用严格路由。 | 默认禁用,路由器将“/foo”和“/foo/”视为相同。 |
您可以像应用程序一样,向 router
添加中间件和 HTTP 方法路由(例如 get
、put
、post
等)。
更多信息请参阅路由。
express.static(root, [options])
这是 Express 中一个内置的中间件函数。它提供静态文件,并基于 serve-static。
注意:为了获得最佳效果,请使用反向代理缓存来提高提供静态资产的性能。
root
参数指定提供静态资产的根目录。该函数通过将 req.url
与提供的 root
目录结合来确定要提供的文件。当文件未找到时,它不会发送 404 响应,而是调用 next()
继续执行下一个中间件,从而允许堆叠和回退。
下表描述了 options
对象的属性。另请参阅下面的示例。
属性 | 描述 | 类型 | 默认值 |
---|---|---|---|
dotfiles |
确定如何处理点文件(以点“.”开头的文件或目录)。 参阅下面的点文件。 |
字符串 | “ignore” |
etag |
启用或禁用 etag 生成 注意: express.static 总是发送弱 ETags。 |
布尔值 | true |
extensions |
设置文件扩展名回退:如果文件未找到,则搜索具有指定扩展名的文件并提供找到的第一个文件。示例:['html', 'htm'] 。 |
混合 | false |
fallthrough |
允许客户端错误作为未处理的请求穿透,否则转发客户端错误。 参阅下面的穿透。 |
布尔值 | true |
immutable |
启用或禁用 Cache-Control 响应头中的 immutable 指令。如果启用,还应指定 maxAge 选项以启用缓存。immutable 指令将阻止受支持的客户端在 maxAge 选项的生命周期内发出条件请求,以检查文件是否已更改。 |
布尔值 | false |
index |
发送指定的目录索引文件。设置为 false 以禁用目录索引。 |
混合 | “index.html” |
lastModified |
将 Last-Modified 头设置为文件在操作系统上的最后修改日期。 |
布尔值 | true |
maxAge |
将 Cache-Control 头部的 max-age 属性设置为毫秒或 ms 格式的字符串。 | 数字 | 0 |
redirect |
当路径名是目录时,重定向到尾部“/”。 | 布尔值 | true |
setHeaders |
用于设置与文件一起提供的 HTTP 头的函数。 参阅下面的setHeaders。 |
函数 |
更多信息请参阅 Express 中提供静态文件和 使用中间件 - 内置中间件。
dotfiles
此选项的可能值为
- “allow” - 对点文件不进行特殊处理。
- “deny” - 拒绝点文件请求,响应
403
,然后调用next()
。 - “ignore” - 视点文件不存在,响应
404
,然后调用next()
。
fallthrough
当此选项为 true
时,客户端错误(例如错误请求或对不存在文件的请求)将导致此中间件简单地调用 next()
以调用堆栈中的下一个中间件。当为 false 时,这些错误(甚至 404)将调用 next(err)
。
将此选项设置为 true
,以便您可以将多个物理目录映射到同一个 Web 地址,或用于路由填充不存在的文件。
如果您已将此中间件挂载到严格的单个文件系统目录路径,请使用 false
,这样可以短路 404 错误以减少开销。此中间件还将响应所有方法。
setHeaders
对于此选项,指定一个函数来设置自定义响应头。对头的更改必须同步发生。
函数的签名是
fn(res, path, stat)
参数
res
,响应对象。path
,正在发送的文件路径。stat
,正在发送的文件的stat
对象。
express.static 示例
这是一个使用带有详细选项对象的 express.static
中间件函数的示例
const options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders (res, path, stat) {
res.set('x-timestamp', Date.now())
}
}
app.use(express.static('public', options))
express.text([options])
这是 Express 中一个内置的中间件函数。它将传入的请求有效负载解析为字符串,并基于 body-parser。
返回一个中间件,该中间件将所有主体解析为字符串,并且只处理 Content-Type
头与 type
选项匹配的请求。此解析器接受主体的任何 Unicode 编码,并支持 gzip
和 deflate
编码的自动解压缩。
在中间件之后,包含已解析数据的新 body
字符串会填充到 request
对象上(即 req.body
),如果没有要解析的主体、Content-Type
不匹配或发生错误,则为 undefined
。
由于 req.body
的结构基于用户控制的输入,因此此对象中的所有属性和值均不可信,在使用前应进行验证。例如,req.body.trim()
可能会以多种方式失败,例如堆叠多个解析器时,req.body
可能来自不同的解析器。建议在调用字符串方法之前测试 req.body
是否为字符串。
下表描述了可选 options
对象的属性。
属性 | 描述 | 类型 | 默认值 |
---|---|---|---|
defaultCharset |
如果请求的 Content-Type 头中未指定字符集,则指定文本内容的默认字符集。 |
字符串 | "utf-8" |
inflate |
启用或禁用处理解压缩(压缩)的主体;禁用时,解压缩的主体将被拒绝。 | 布尔值 | true |
limit |
控制最大请求主体大小。如果是数字,则值指定字节数;如果是字符串,则值传递给 bytes 库进行解析。 | 混合 | "100kb" |
type |
这用于确定中间件将解析的媒体类型。此选项可以是字符串、字符串数组或函数。如果不是函数,type 选项直接传递给 type-is 库,这可以是扩展名(如 txt )、MIME 类型(如 text/plain ),或带有通配符的 MIME 类型(如 */* 或 text/* )。如果是函数,type 选项将作为 fn(req) 调用,如果它返回一个真值,则解析请求。 |
混合 | "text/plain" |
verify |
如果提供此选项,它将作为 verify(req, res, buf, encoding) 调用,其中 buf 是原始请求主体的 Buffer ,encoding 是请求的编码。解析可以通过抛出错误来中止。 |
函数 | undefined |
express.urlencoded([options])
这是 Express 中一个内置的中间件函数。它解析带有 urlencoded 有效负载的传入请求,并基于 body-parser。
返回一个中间件,该中间件只解析 urlencoded 主体,并且只处理 Content-Type
头与 type
选项匹配的请求。此解析器只接受主体的 UTF-8 编码,并支持 gzip
和 deflate
编码的自动解压缩。
在中间件之后,包含已解析数据的新 body
对象会填充到 request
对象上(即 req.body
),如果没有要解析的主体、Content-Type
不匹配或发生错误,则为 undefined
。此对象将包含键值对,其中值可以是字符串或数组(当 extended
为 false
时),或任何类型(当 extended
为 true
时)。
由于 req.body
的结构基于用户控制的输入,因此此对象中的所有属性和值均不可信,在使用前应进行验证。例如,req.body.foo.toString()
可能会以多种方式失败,例如 foo
可能不存在或不是字符串,并且 toString
可能不是函数,而是字符串或其他用户输入。
下表描述了可选 options
对象的属性。
属性 | 描述 | 类型 | 默认值 |
---|---|---|---|
extended |
此选项允许选择使用 querystring 库(当为 false 时)还是 qs 库(当为 true 时)来解析 URL 编码的数据。“扩展”语法允许将富对象和数组编码为 URL 编码格式,从而提供类似 JSON 的 URL 编码体验。更多信息请参阅 qs 库。 |
布尔值 | false |
inflate |
启用或禁用处理解压缩(压缩)的主体;禁用时,解压缩的主体将被拒绝。 | 布尔值 | true |
limit |
控制最大请求主体大小。如果是数字,则值指定字节数;如果是字符串,则值传递给 bytes 库进行解析。 | 混合 | "100kb" |
parameterLimit |
此选项控制 URL 编码数据中允许的最大参数数量。如果请求包含的参数数量超过此值,将引发错误。 | 数字 | 1000 |
type |
这用于确定中间件将解析的媒体类型。此选项可以是字符串、字符串数组或函数。如果不是函数,type 选项直接传递给 type-is 库,这可以是扩展名(如 urlencoded )、MIME 类型(如 application/x-www-form-urlencoded ),或带有通配符的 MIME 类型(如 */x-www-form-urlencoded )。如果是函数,type 选项将作为 fn(req) 调用,如果它返回一个真值,则解析请求。 |
混合 | "application/x-www-form-urlencoded" |
verify |
如果提供此选项,它将作为 verify(req, res, buf, encoding) 调用,其中 buf 是原始请求主体的 Buffer ,encoding 是请求的编码。解析可以通过抛出错误来中止。 |
函数 | undefined |
应用程序
app
对象通常表示 Express 应用程序。通过调用 Express 模块导出的顶级 express()
函数来创建它
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000)
app
对象具有以下方法:
- 路由 HTTP 请求;例如,请参阅 app.METHOD 和 app.param。
- 配置中间件;请参阅 app.route。
- 渲染 HTML 视图;请参阅 app.render。
- 注册模板引擎;请参阅 app.engine。
它还具有影响应用程序行为的设置(属性);更多信息请参阅应用程序设置。
属性
app.locals
app.locals
对象包含应用程序内的局部变量,这些变量在通过 res.render 渲染的模板中可用。
locals
对象由视图引擎用于渲染响应。对象键可能特别敏感,不应包含用户控制的输入,因为它可能影响视图引擎的操作或导致跨站脚本攻击。
console.dir(app.locals.title)
// => 'My App'
console.dir(app.locals.email)
// => '[email protected]'
有关其他注意事项,请查阅所用视图引擎的文档。一旦设置,app.locals
属性的值在应用程序的整个生命周期内都保持不变,而 res.locals 属性仅在请求的生命周期内有效。
您可以在应用程序内渲染的模板中访问局部变量。这对于为模板提供辅助函数以及应用程序级数据非常有用。局部变量通过 req.app.locals
在中间件中可用(参阅 req.app)。
app.locals.title = 'My App'
app.locals.strftime = require('strftime')
app.locals.email = '[email protected]'
app.mountpath
app.mountpath
属性包含子应用程序被挂载的一个或多个路径模式。
子应用程序是 express
的一个实例,可用于处理路由请求。
const express = require('express')
const app = express() // the main app
const admin = express() // the sub app
admin.get('/', (req, res) => {
console.log(admin.mountpath) // /admin
res.send('Admin Homepage')
})
app.use('/admin', admin) // mount the sub app
它类似于 req
对象的 baseUrl 属性,不同之处在于 req.baseUrl
返回匹配的 URL 路径,而不是匹配的模式。
如果子应用程序被挂载到多个路径模式上,app.mountpath
将返回其被挂载的模式列表,如以下示例所示。
const admin = express()
admin.get('/', (req, res) => {
console.log(admin.mountpath) // [ '/adm{*splat}n', '/manager' ]
res.send('Admin Homepage')
})
const secret = express()
secret.get('/', (req, res) => {
console.log(secret.mountpath) // /secr{*splat}t
res.send('Admin Secret')
})
admin.use('/secr{*splat}t', secret) // load the 'secret' router on '/secr{*splat}t', on the 'admin' sub app
app.use(['/adm{*splat}n', '/manager'], admin) // load the 'admin' router on '/adm{*splat}n' and '/manager', on the parent app
app.router
应用程序内置的路由器实例。这是惰性创建的,在首次访问时创建。
const express = require('express')
const app = express()
const router = app.router
router.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000)
您可以像应用程序一样,向 router
添加中间件和 HTTP 方法路由。
更多信息请参阅路由。
事件
app.on('mount', callback(parent))
当子应用程序被挂载到父应用程序上时,mount
事件会在子应用程序上触发。父应用程序会作为参数传递给回调函数。
const admin = express()
admin.on('mount', (parent) => {
console.log('Admin Mounted')
console.log(parent) // refers to the parent app
})
admin.get('/', (req, res) => {
res.send('Admin Homepage')
})
app.use('/admin', admin)
方法
app.all(path, callback [, callback ...])
此方法类似于标准的 app.METHOD() 方法,但它匹配所有 HTTP 动词。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
示例
以下回调函数将针对 /secret
的请求执行,无论使用 GET、POST、PUT、DELETE 或任何其他 HTTP 请求方法
app.all('/secret', (req, res, next) => {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
app.all()
方法对于将“全局”逻辑映射到特定的路径前缀或任意匹配非常有用。例如,如果您将以下内容放在所有其他路由定义之上,它将要求从此时起的所有路由都需要身份验证,并自动加载用户。请记住,这些回调函数不必充当端点:loadUser
可以执行任务,然后调用 next()
以继续匹配后续路由。
app.all('{*splat}', requireAuthentication, loadUser)
或等效代码
app.all('{*splat}', requireAuthentication)
app.all('{*splat}', loadUser)
另一个例子是白名单化的“全局”功能。该示例类似于上述示例,但它只限制以“/api”开头的路径
app.all('/api/{*splat}', requireAuthentication)
app.delete(path, callback [, callback ...])
将 HTTP DELETE 请求路由到指定路径,并使用指定的回调函数。更多信息请参阅路由指南。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
示例
app.delete('/', (req, res) => {
res.send('DELETE request to homepage')
})
app.disable(name)
将布尔设置 name
设置为 false
,其中 name
是应用程序设置表中的一个属性。对于布尔属性,调用 app.set('foo', false)
等同于调用 app.disable('foo')
。
例如
app.disable('trust proxy')
app.get('trust proxy')
// => false
app.disabled(name)
如果布尔设置 name
被禁用(false
),则返回 true
,其中 name
是应用程序设置表中的一个属性。
app.disabled('trust proxy')
// => true
app.enable('trust proxy')
app.disabled('trust proxy')
// => false
app.enable(name)
将布尔设置 name
设置为 true
,其中 name
是应用程序设置表中的一个属性。对于布尔属性,调用 app.set('foo', true)
等同于调用 app.enable('foo')
。
app.enable('trust proxy')
app.get('trust proxy')
// => true
app.enabled(name)
如果设置 name
被启用(true
),则返回 true
,其中 name
是应用程序设置表中的一个属性。
app.enabled('trust proxy')
// => false
app.enable('trust proxy')
app.enabled('trust proxy')
// => true
app.engine(ext, callback)
将给定的模板引擎 callback
注册为 ext
。
默认情况下,Express 将根据文件扩展名 require()
引擎。例如,如果您尝试渲染一个“foo.pug”文件,Express 会在内部调用以下内容,并在后续调用时缓存 require()
以提高性能。
app.engine('pug', require('pug').__express)
对于那些不提供 .__express
的引擎,或者您希望将不同的扩展名“映射”到模板引擎时,请使用此方法。
例如,将 EJS 模板引擎映射到“.html”文件:
app.engine('html', require('ejs').renderFile)
在这种情况下,EJS 提供了一个具有 Express 预期相同签名的 .renderFile()
方法:(path, options, callback)
,但请注意,它在内部将此方法别名为 ejs.__express
,因此如果您使用“.ejs”扩展名,则无需执行任何操作。
某些模板引擎不遵循此约定。consolidate.js 库将 Node 模板引擎映射到遵循此约定,以便它们与 Express 无缝协作。
const engines = require('consolidate')
app.engine('haml', engines.haml)
app.engine('html', engines.hogan)
app.get(name)
返回 name
应用程序设置的值,其中 name
是应用程序设置表中的一个字符串。例如
app.get('title')
// => undefined
app.set('title', 'My Site')
app.get('title')
// => "My Site"
app.get(path, callback [, callback ...])
将 HTTP GET 请求路由到指定路径,并使用指定的回调函数。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
更多信息请参阅路由指南。
示例
app.get('/', (req, res) => {
res.send('GET request to homepage')
})
app.listen(path, [callback])
启动一个 UNIX 套接字并在给定路径上监听连接。此方法与 Node 的 http.Server.listen() 完全相同。
const express = require('express')
const app = express()
app.listen('/tmp/sock')
app.listen([port[, host[, backlog]]][, callback])
绑定并监听指定主机和端口上的连接。此方法与 Node 的 http.Server.listen() 完全相同。
如果省略端口或端口为 0,操作系统将分配一个任意未使用的端口,这对于自动化任务(测试等)等情况非常有用。
const express = require('express')
const app = express()
app.listen(3000)
express()
返回的 app
实际上是一个 JavaScript Function
,旨在作为回调函数传递给 Node 的 HTTP 服务器以处理请求。这使得使用相同的代码库为您的应用程序提供 HTTP 和 HTTPS 版本变得容易,因为应用程序不继承这些(它只是一个回调)
const express = require('express')
const https = require('https')
const http = require('http')
const app = express()
http.createServer(app).listen(80)
https.createServer(options, app).listen(443)
app.listen()
方法返回一个 http.Server 对象,并且(对于 HTTP)是以下内容的便捷方法
app.listen = function () {
const server = http.createServer(this)
return server.listen.apply(server, arguments)
}
注意
实际上支持 Node 的 http.Server.listen() 方法的所有形式。
app.METHOD(path, callback [, callback ...])
路由 HTTP 请求,其中 METHOD 是请求的 HTTP 方法,例如 GET、PUT、POST 等,采用小写形式。因此,实际方法是 app.get()
、app.post()
、app.put()
等。完整列表请参阅下面的路由方法。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
路由方法
Express 支持以下与同名 HTTP 方法对应的路由方法
|
|
|
API 文档仅包含最流行的 HTTP 方法 app.get()
、app.post()
、app.put()
和 app.delete()
的明确条目。但是,上面列出的其他方法也以完全相同的方式工作。
要路由转换为无效 JavaScript 变量名的方法,请使用方括号表示法。例如,app['m-search']('/', function ...
。
如果在调用 app.get()
之前没有为该路径调用 app.head()
,则 app.get()
函数除了 GET
方法外,还会自动为 HTTP HEAD
方法调用。
app.all()
方法不派生自任何 HTTP 方法,并为所有 HTTP 请求方法在指定路径加载中间件。更多信息请参阅app.all。
更多路由信息请参阅路由指南。
app.param(name, callback)
为路由参数添加回调触发器,其中 name
是参数的名称或它们的数组,callback
是回调函数。回调函数的参数依次是请求对象、响应对象、下一个中间件、参数的值和参数的名称。
如果 name
是一个数组,则 callback
触发器将按照声明顺序为其中声明的每个参数注册。此外,对于除了最后一个参数之外的每个声明参数,回调内部对 next
的调用将调用下一个声明参数的回调。对于最后一个参数,对 next
的调用将调用当前正在处理的路由的下一个中间件,就像 name
只是一个字符串时一样。
例如,当路由路径中存在 :user
时,您可以映射用户加载逻辑以自动向路由提供 req.user
,或对参数输入执行验证。
app.param('user', (req, res, next, id) => {
// try to get the user details from the User model and attach it to the request object
User.find(id, (err, user) => {
if (err) {
next(err)
} else if (user) {
req.user = user
next()
} else {
next(new Error('failed to load user'))
}
})
})
参数回调函数是它们所定义的路由器的局部函数。它们不会被挂载的应用程序或路由器继承,也不会为从父路由器继承的路由参数触发。因此,在 app
上定义的参数回调仅由在 app
路由上定义的路由参数触发。
所有参数回调将在参数出现的任何路由的任何处理程序之前调用,并且在请求-响应周期中每个回调只会被调用一次,即使参数在多个路由中匹配,如以下示例所示。
app.param('id', (req, res, next, id) => {
console.log('CALLED ONLY ONCE')
next()
})
app.get('/user/:id', (req, res, next) => {
console.log('although this matches')
next()
})
app.get('/user/:id', (req, res) => {
console.log('and this matches too')
res.end()
})
在 GET /user/42
上,打印以下内容
CALLED ONLY ONCE
although this matches
and this matches too
app.param(['id', 'page'], (req, res, next, value) => {
console.log('CALLED ONLY ONCE with', value)
next()
})
app.get('/user/:id/:page', (req, res, next) => {
console.log('although this matches')
next()
})
app.get('/user/:id/:page', (req, res) => {
console.log('and this matches too')
res.end()
})
在 GET /user/42/3
上,打印以下内容
CALLED ONLY ONCE with 42
CALLED ONLY ONCE with 3
although this matches
and this matches too
app.path()
返回应用程序的规范路径,一个字符串。
const app = express()
const blog = express()
const blogAdmin = express()
app.use('/blog', blog)
blog.use('/admin', blogAdmin)
console.log(app.path()) // ''
console.log(blog.path()) // '/blog'
console.log(blogAdmin.path()) // '/blog/admin'
在复杂的挂载应用程序情况下,此方法的行为可能变得非常复杂:通常最好使用 req.baseUrl 来获取应用程序的规范路径。
app.post(path, callback [, callback ...])
将 HTTP POST 请求路由到指定路径,并使用指定的回调函数。更多信息请参阅路由指南。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
示例
app.post('/', (req, res) => {
res.send('POST request to homepage')
})
app.put(path, callback [, callback ...])
将 HTTP PUT 请求路由到指定路径,并使用指定的回调函数。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
示例
app.put('/', (req, res) => {
res.send('PUT request to homepage')
})
app.render(view, [locals], callback)
通过 callback
函数返回视图的渲染 HTML。它接受一个可选参数,该参数是一个包含视图局部变量的对象。它类似于 res.render(),但它不能单独将渲染的视图发送到客户端。
将 app.render()
视为一个用于生成渲染视图字符串的实用函数。内部 res.render()
使用 app.render()
来渲染视图。
view
参数执行文件系统操作,例如从磁盘读取文件和评估 Node.js 模块,因此出于安全原因,不应包含来自最终用户的输入。
locals
对象由视图引擎用于渲染响应。对象键可能特别敏感,不应包含用户控制的输入,因为它可能影响视图引擎的操作或导致跨站脚本攻击。
局部变量 cache
保留用于启用视图缓存。如果您想在开发过程中缓存视图,请将其设置为 true
;视图缓存在生产环境中默认启用。
app.render('email', (err, html) => {
// ...
})
app.render('email', { name: 'Tobi' }, (err, html) => {
// ...
})
app.route(path)
返回单个路由的实例,然后您可以使用它来处理带有可选中间件的 HTTP 动词。使用 app.route()
可以避免重复的路由名称(从而避免拼写错误)。
const app = express()
app.route('/events')
.all((req, res, next) => {
// runs for all HTTP verbs first
// think of it as route specific middleware!
})
.get((req, res, next) => {
res.json({})
})
.post((req, res, next) => {
// maybe add a new event...
})
app.set(name, value)
将设置 name
分配给 value
。您可以存储任何您想要的值,但某些名称可用于配置服务器的行为。这些特殊名称列在应用程序设置表中。
对于布尔属性,调用 app.set('foo', true)
等同于调用 app.enable('foo')
。同样,对于布尔属性,调用 app.set('foo', false)
等同于调用 app.disable('foo')
。
使用 app.get()
检索设置的值。
app.set('title', 'My Site')
app.get('title') // "My Site"
应用程序设置
下表列出了应用程序设置。
请注意,子应用程序将
- 不会继承具有默认值的设置。您必须在子应用程序中设置该值。
- 继承没有默认值的设置;这些在下表中明确注明。
例外:子应用程序将继承 trust proxy
的值,即使它有默认值(为了向后兼容);子应用程序在生产环境中(当 NODE_ENV
为“production”时)不会继承 view cache
的值。
属性 | 类型 | 描述 | 默认值 |
---|---|---|---|
|
布尔值 | 启用大小写敏感。启用时,“/Foo”和“/foo”是不同的路由。禁用时,“/Foo”和“/foo”被视为相同。 注意:子应用程序将继承此设置的值。 |
不适用(未定义) |
|
字符串 | 环境模式。请务必在生产环境中设置为“production”;请参阅生产最佳实践:性能和可靠性。 |
|
|
可变 |
设置 ETag 响应头。可能的值请参阅 |
|
|
字符串 | 指定默认的 JSONP 回调名称。 |
“callback” |
|
布尔值 |
启用对来自 注意:子应用程序将继承此设置的值。 |
不适用(未定义) |
|
可变 | `JSON.stringify` 使用的“replacer”参数。 注意:子应用程序将继承此设置的值。 |
不适用(未定义) |
|
可变 | `JSON.stringify` 使用的“space”参数。这通常设置为用于缩进美化 JSON 的空格数。 注意:子应用程序将继承此设置的值。 |
不适用(未定义) |
|
可变 |
通过将值设置为 简单查询解析器基于 Node 的原生查询解析器 querystring。 扩展查询解析器基于 qs。 自定义查询字符串解析函数将接收完整的查询字符串,并且必须返回一个包含查询键及其值的对象。 |
"simple" |
|
布尔值 | 启用严格路由。启用时,路由器将“/foo”和“/foo/”视为不同。否则,路由器将“/foo”和“/foo/”视为相同。 注意:子应用程序将继承此设置的值。 |
不适用(未定义) |
|
数字 | 要删除的主机中以点分隔的部分数量,以访问子域。 | 2 |
|
可变 |
指示应用程序位于前端代理之后,并使用 启用时,Express 会尝试确定通过前端代理或一系列代理连接的客户端的 IP 地址。
注意:子应用程序会继承此设置的值,即使它有默认值。 |
|
|
字符串或数组 | 应用程序视图的一个目录或多个目录数组。如果是数组,视图将按照它们在数组中出现的顺序查找。 |
|
|
布尔值 | 启用视图模板编译缓存。 注意:子应用程序在生产环境中(当 |
生产环境中为 |
|
字符串 | 省略时使用的默认引擎扩展名。 注意:子应用程序将继承此设置的值。 |
不适用(未定义) |
|
布尔值 | 启用“X-Powered-By: Express”HTTP 头。 |
|
trust proxy
设置的选项
阅读代理后的 Express 了解更多信息。
类型 | 值 |
---|---|
布尔值 |
如果为 如果为 |
字符串 包含逗号分隔值的字符串 字符串数组 |
要信任的 IP 地址、子网或 IP 地址和子网数组。预配置的子网名称为:
通过以下任一方式设置 IP 地址: 指定单个子网
指定子网和地址
指定多个子网(CSV 格式)
指定多个子网(数组格式)
指定时,IP 地址或子网将从地址确定过程中排除,距离应用程序服务器最近的不可信 IP 地址被确定为客户端的 IP 地址。 |
数字 |
将前端代理服务器的第 N 跳作为客户端信任。 |
函数 |
自定义信任实现。仅当您知道自己在做什么时才使用此功能。
|
etag
设置的选项
注意:这些设置仅适用于动态文件,而不适用于静态文件。express.static 中间件会忽略这些设置。
ETag 功能是使用 etag 包实现的。更多信息请参阅其文档。
类型 | 值 |
---|---|
布尔值 |
|
字符串 | 如果是“strong”,启用强 ETag。 如果是“weak”,启用弱 ETag。 |
函数 |
自定义 ETag 函数实现。仅当您知道自己在做什么时才使用此功能。
|
app.use([path,] callback [, callback...])
在指定路径挂载指定的中间件函数或多个函数:当请求路径的根与 path
匹配时,中间件函数将被执行。
参数
参数 | 描述 | 默认值 |
---|---|---|
path |
调用中间件函数的路径;可以是以下任何一种:
|
'/'(根路径) |
callback |
回调函数;可以是:
您可以提供多个行为类似于中间件的回调函数,但这些回调函数可以调用 当回调函数抛出错误或返回一个被拒绝的 Promise 时,`next(err)` 将自动被调用。 由于 router 和 app 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。 示例请参阅中间件回调函数示例。 |
无 |
描述
一个路由将匹配其路径后紧跟“/
”的任何路径。例如:app.use('/apple', ...)
将匹配“/apple”、“/apple/images”、“/apple/images/news”等。
由于 path
默认为“/”,因此未指定路径挂载的中间件将对应用程序的每个请求执行。例如,此中间件函数将对应用程序的每个请求执行
app.use((req, res, next) => {
console.log('Time: %d', Date.now())
next()
})
中间件函数按顺序执行,因此中间件的包含顺序很重要。
// this middleware will not allow the request to go beyond it
app.use((req, res, next) => {
res.send('Hello World')
})
// requests will never reach this route
app.get('/', (req, res) => {
res.send('Welcome')
})
错误处理中间件
错误处理中间件总是接收四个参数。您必须提供四个参数才能将其识别为错误处理中间件函数。即使您不需要使用 next
对象,也必须指定它以保持签名。否则,next
对象将被解释为常规中间件,并且无法处理错误。有关错误处理中间件的详细信息,请参阅:错误处理。
定义错误处理中间件函数的方式与其他中间件函数相同,只是使用四个参数而不是三个,具体签名为 (err, req, res, next)
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
路径示例
下表提供了一些用于挂载中间件的有效 path
值的简单示例。
类型 | 示例 |
---|---|
路径 |
这将匹配以
|
路径模式 |
这将匹配以
|
正则表达式 |
这将匹配以
|
数组 |
这将匹配以
|
中间件回调函数示例
下表提供了一些简单的中间件函数示例,它们可以用作 app.use()
、app.METHOD()
和 app.all()
的 callback
参数。
用法 | 示例 |
---|---|
单个中间件 |
您可以本地定义和挂载一个中间件函数。
路由器是有效的中间件。
Express 应用程序是有效的中间件。
|
中间件系列 |
您可以在同一挂载路径指定多个中间件函数。
|
数组 |
使用数组按逻辑对中间件进行分组。
|
组合 |
您可以组合上述所有挂载中间件的方式。
|
以下是在 Express 应用程序中使用 express.static 中间件的一些示例。
从应用程序目录中的“public”目录提供应用程序的静态内容
// GET /style.css etc
app.use(express.static(path.join(__dirname, 'public')))
将中间件挂载到“/static”,以便仅当请求路径以“/static”为前缀时才提供静态内容
// GET /static/style.css etc.
app.use('/static', express.static(path.join(__dirname, 'public')))
通过在静态中间件之后加载日志中间件来禁用静态内容请求的日志记录
app.use(express.static(path.join(__dirname, 'public')))
app.use(logger())
从多个目录提供静态文件,但优先考虑“./public”而不是其他目录
app.use(express.static(path.join(__dirname, 'public')))
app.use(express.static(path.join(__dirname, 'files')))
app.use(express.static(path.join(__dirname, 'uploads')))
请求
req
对象表示 HTTP 请求,并具有请求查询字符串、参数、正文、HTTP 头等属性。在本文档中,按照惯例,该对象始终被称为 req
(HTTP 响应为 res
),但其实际名称由您正在使用的回调函数的参数决定。
例如
app.get('/user/:id', (req, res) => {
res.send(`user ${req.params.id}`)
})
但您也可以有
app.get('/user/:id', (request, response) => {
response.send(`user ${request.params.id}`)
})
req
对象是 Node 自己的请求对象的增强版本,并支持所有内置字段和方法。
属性
在 Express 4 中,req
对象上默认不再提供 req.files
。要访问 req.files
对象上的上传文件,请使用多部分处理中间件,例如 busboy、multer、formidable、multiparty、connect-multiparty 或 pez。
req.app
此属性引用正在使用该中间件的 Express 应用程序实例。
如果您遵循的模式是创建一个只导出中间件函数并在主文件中 require()
它的模块,那么该中间件可以通过 req.app
访问 Express 实例
例如
// index.js
app.get('/viewdirectory', require('./mymiddleware.js'))
// mymiddleware.js
module.exports = (req, res) => {
res.send(`The views directory is ${req.app.get('views')}`)
}
req.baseUrl
路由器实例被挂载的 URL 路径。
req.baseUrl
属性类似于 app
对象的mountpath 属性,不同之处在于 app.mountpath
返回匹配的路径模式。
例如
const greet = express.Router()
greet.get('/jp', (req, res) => {
console.log(req.baseUrl) // /greet
res.send('Konichiwa!')
})
app.use('/greet', greet) // load the router on '/greet'
即使您使用路径模式或一组路径模式来加载路由器,baseUrl
属性也会返回匹配的字符串,而不是模式。在以下示例中,greet
路由器加载在两个路径模式上。
app.use(['/gre:"param"t', '/hel{l}o'], greet) // load the router on '/gre:"param"t' and '/hel{l}o'
当请求发送到 /greet/jp
时,req.baseUrl
是“/greet”。当请求发送到 /hello/jp
时,req.baseUrl
是“/hello”。
req.body
包含请求主体中提交数据的键值对。默认情况下,它为 undefined
,当您使用像 express.json()
或 express.urlencoded()
这样的主体解析中间件时,它会被填充。
由于 req.body
的结构基于用户控制的输入,因此此对象中的所有属性和值均不可信,在使用前应进行验证。例如,req.body.foo.toString()
可能会以多种方式失败,例如 foo
可能不存在或不是字符串,并且 toString
可能不是函数,而是字符串或其他用户输入。
以下示例展示了如何使用主体解析中间件来填充 req.body
。
const express = require('express')
const app = express()
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
app.post('/profile', (req, res, next) => {
console.log(req.body)
res.json(req.body)
})
req.cookies
当使用 cookie-parser 中间件时,此属性是一个包含请求发送的 cookie 的对象。如果请求不包含任何 cookie,它默认为 {}
。
// Cookie: name=tj
console.dir(req.cookies.name)
// => "tj"
如果 cookie 已签名,则必须使用 req.signedCookies。
更多信息、问题或疑虑,请参阅 cookie-parser。
req.fresh
当响应在客户端缓存中仍然“新鲜”时,返回 true
,否则返回 false
表示客户端缓存已过期,应发送完整响应。
当客户端发送 Cache-Control: no-cache
请求头以指示端到端重新加载请求时,此模块将返回 false
以使这些请求的处理透明化。
缓存验证工作原理的更多详细信息可在 HTTP/1.1 缓存规范中找到。
console.dir(req.fresh)
// => true
req.host
包含从 Host
HTTP 头派生出的主机。
当trust proxy
设置不评估为 false
时,此属性将改为从 X-Forwarded-Host
头字段获取值。此头可以由客户端或代理设置。
如果请求中有多个 X-Forwarded-Host
头,则使用第一个头的值。这包括一个带有逗号分隔值的单个头,其中使用第一个值。
// Host: "example.com:3000"
console.dir(req.host)
// => 'example.com:3000'
// Host: "[::1]:3000"
console.dir(req.host)
// => '[::1]:3000'
req.hostname
包含从 Host
HTTP 头派生出的主机名。
当trust proxy
设置不评估为 false
时,此属性将改为从 X-Forwarded-Host
头字段获取值。此头可以由客户端或代理设置。
如果请求中有多个 X-Forwarded-Host
头,则使用第一个头的值。这包括一个带有逗号分隔值的单个头,其中使用第一个值。
在 Express v4.17.0 之前,X-Forwarded-Host
不能包含多个值或多次出现。
// Host: "example.com:3000"
console.dir(req.hostname)
// => 'example.com'
req.ip
包含请求的远程 IP 地址。
当trust proxy
设置不评估为 false
时,此属性的值派生自 X-Forwarded-For
头中最左边的条目。此头可以由客户端或代理设置。
console.dir(req.ip)
// => "127.0.0.1"
req.ips
当trust proxy
设置不评估为 false
时,此属性包含 X-Forwarded-For
请求头中指定的 IP 地址数组。否则,它包含一个空数组。此头可以由客户端或代理设置。
例如,如果 X-Forwarded-For
是 client, proxy1, proxy2
,则 req.ips
将是 ["client", "proxy1", "proxy2"]
,其中 proxy2
是最下游的。
req.method
包含与请求的 HTTP 方法对应的字符串:GET
、POST
、PUT
等。
req.originalUrl
req.url
不是 Express 的原生属性,它继承自 Node 的 http 模块。
此属性非常类似于 req.url
;但是,它保留了原始请求 URL,允许您为了内部路由目的自由重写 req.url
。例如,app.use() 的“挂载”功能将重写 req.url
以剥离挂载点。
// GET /search?q=something
console.dir(req.originalUrl)
// => "/search?q=something"
req.originalUrl
在中间件和路由器对象中都可用,是 req.baseUrl
和 req.url
的组合。考虑以下示例
// GET 'http://www.example.com/admin/new?sort=desc'
app.use('/admin', (req, res, next) => {
console.dir(req.originalUrl) // '/admin/new?sort=desc'
console.dir(req.baseUrl) // '/admin'
console.dir(req.path) // '/new'
next()
})
req.params
此属性是一个对象,其中包含映射到命名路由“参数”的属性。例如,如果您有路由 /user/:name
,那么“name”属性可以通过 req.params.name
访问。此对象默认为 {}
。
// GET /user/tj
console.dir(req.params.name)
// => "tj"
当您使用正则表达式进行路由定义时,捕获组将通过 req.params[n]
在数组中提供,其中 n
是第 n 个捕获组。
app.use(/^\/file\/(.*)$/, (req, res) => {
// GET /file/javascripts/jquery.js
console.dir(req.params[0])
// => "javascripts/jquery.js"
})
如果您需要更改 req.params
中的键,请使用 app.param 处理程序。更改仅适用于已在路由路径中定义的参数。
在中间件或路由处理程序中对 req.params
对象所做的任何更改都将被重置。
注意
Express 自动解码 req.params
中的值(使用 decodeURIComponent
)。
req.path
包含请求 URL 的路径部分。
// example.com/users?sort=desc
console.dir(req.path)
// => "/users"
当从中间件调用时,挂载点不包含在 req.path
中。更多详情请参阅 app.use()。
req.protocol
包含请求协议字符串:http
或(对于 TLS 请求)https
。
当trust proxy
设置不评估为 false
时,如果存在 X-Forwarded-Proto
头字段,则此属性将使用其值。此头可以由客户端或代理设置。
console.dir(req.protocol)
// => "http"
req.query
此属性是一个对象,其中包含路由中每个查询字符串参数的属性。当查询解析器设置为禁用时,它是一个空对象 {}
,否则它是配置的查询解析器的结果。
由于 req.query
的结构基于用户控制的输入,因此此对象中的所有属性和值均不可信,在使用前应进行验证。例如,req.query.foo.toString()
可能会以多种方式失败,例如 foo
可能不存在或不是字符串,并且 toString
可能不是函数,而是字符串或其他用户输入。
此属性的值可以通过查询解析器应用程序设置进行配置,以满足您的应用程序需求。一个非常流行的查询字符串解析器是 qs
模块,默认情况下使用它。qs
模块配置非常灵活,有许多设置,可能需要使用与默认设置不同的设置来填充 req.query
。
const qs = require('qs')
app.set('query parser',
(str) => qs.parse(str, { /* custom options */ }))
查看查询解析器应用程序设置文档以了解其他自定义选项。
req.res
此属性引用与此请求对象相关的响应对象。
req.route
包含当前匹配的路由,一个字符串。例如
app.get('/user/{:id}', (req, res) => {
console.dir(req.route, { depth: null })
res.send('GET')
})
上述代码片段的示例输出
Route {
path: '/user/{:id}',
stack: [
Layer {
handle: [Function (anonymous)],
keys: [],
name: '<anonymous>',
params: undefined,
path: undefined,
slash: false,
matchers: [ [Function: match] ],
method: 'get'
}
],
methods: [Object: null prototype] { get: true }
}
req.secure
如果建立 TLS 连接,则为 true 的布尔属性。等同于以下内容
req.protocol === 'https'
req.signedCookies
当使用 cookie-parser 中间件时,此属性包含请求发送的签名 cookie,这些 cookie 已解签并可供使用。签名 cookie 位于不同的对象中以显示开发人员意图;否则,恶意攻击可能会针对 req.cookie
值(这些值很容易被欺骗)。请注意,签名 cookie 并不会使其“隐藏”或加密;它只是防止篡改(因为用于签名的密钥是私密的)。
如果没有发送签名 cookie,该属性默认为 {}
。
// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
console.dir(req.signedCookies.user)
// => "tobi"
更多信息、问题或疑虑,请参阅 cookie-parser。
req.stale
指示请求是否“过时”,与 req.fresh
相反。更多信息请参阅 req.fresh。
console.dir(req.stale)
// => true
req.subdomains
请求域名中的子域数组。
// Host: "tobi.ferrets.example.com"
console.dir(req.subdomains)
// => ["ferrets", "tobi"]
应用程序属性 subdomain offset
默认为 2,用于确定子域段的起始位置。要更改此行为,请使用 app.set 更改其值。
req.xhr
一个布尔属性,如果请求的 X-Requested-With
头字段是“XMLHttpRequest”,则为 true
,表示该请求是由 jQuery 等客户端库发出的。
console.dir(req.xhr)
// => true
方法
req.accepts(types)
根据请求的 Accept
HTTP 头字段,检查指定的内容类型是否可接受。该方法返回最佳匹配,如果指定的任何内容类型都不可接受,则返回 false
(在这种情况下,应用程序应响应 406 "Not Acceptable"
)。
`type` 值可以是单个 MIME 类型字符串(例如“application/json”)、扩展名(例如“json”)、逗号分隔列表或数组。对于列表或数组,该方法返回最佳匹配项(如果有)。
// Accept: text/html
req.accepts('html')
// => "html"
// Accept: text/*, application/json
req.accepts('html')
// => "html"
req.accepts('text/html')
// => "text/html"
req.accepts(['json', 'text'])
// => "json"
req.accepts('application/json')
// => "application/json"
// Accept: text/*, application/json
req.accepts('image/png')
req.accepts('png')
// => false
// Accept: text/*;q=.5, application/json
req.accepts(['html', 'json'])
// => "json"
如需了解更多信息,或遇到问题,请参阅 accepts。
`req.acceptsCharsets(charset [, ...])`
根据请求的 `Accept-Charset` HTTP 头字段,返回指定字符集中第一个可接受的字符集。如果指定的字符集均不被接受,则返回 `false`。
如需了解更多信息,或遇到问题,请参阅 accepts。
`req.acceptsEncodings(encoding [, ...])`
根据请求的 `Accept-Encoding` HTTP 头字段,返回指定编码中第一个可接受的编码。如果指定的编码均不被接受,则返回 `false`。
如需了解更多信息,或遇到问题,请参阅 accepts。
`req.acceptsLanguages([lang, ...])`
根据请求的 `Accept-Language` HTTP 头字段,返回指定语言中第一个可接受的语言。如果指定的语言均不被接受,则返回 `false`。
如果未提供 `lang` 参数,则 `req.acceptsLanguages()` 将以 `Array` 形式返回 HTTP `Accept-Language` 头中的所有语言。
如需了解更多信息,或遇到问题,请参阅 accepts。
Express (5.x) 源代码:request.js 第 172 行
Accepts (2.0) 源代码:index.js 第 195 行
`req.get(field)`
返回指定的 HTTP 请求头字段(不区分大小写匹配)。`Referrer` 和 `Referer` 字段可互换使用。
req.get('Content-Type')
// => "text/plain"
req.get('content-type')
// => "text/plain"
req.get('Something')
// => undefined
别名为 `req.header(field)`。
`req.is(type)`
如果传入请求的“Content-Type”HTTP 头字段与 `type` 参数指定的 MIME 类型匹配,则返回匹配的内容类型。如果请求没有正文,则返回 `null`。否则返回 `false`。
// With Content-Type: text/html; charset=utf-8
req.is('html') // => 'html'
req.is('text/html') // => 'text/html'
req.is('text/*') // => 'text/*'
// When Content-Type is application/json
req.is('json') // => 'json'
req.is('application/json') // => 'application/json'
req.is('application/*') // => 'application/*'
req.is('html')
// => false
如需了解更多信息,或遇到问题,请参阅 type-is。
`req.range(size[, options])`
`Range` 头解析器。
`size` 参数是资源的最大大小。
`options` 参数是一个对象,可以具有以下属性。
属性 | 类型 | 描述 |
---|---|---|
combine |
布尔值 | 指定重叠和相邻范围是否应合并,默认为 `false`。当为 `true` 时,范围将被合并并返回,就像它们在头部中那样指定一样。 |
将返回一个范围数组,或表示解析错误的负数。
- `-2` 表示头部字符串格式错误
- `-1` 表示无法满足的范围
// parse header from request
const range = req.range(1000)
// the type of the range
if (range.type === 'bytes') {
// the ranges
range.forEach((r) => {
// do something with r.start and r.end
})
}
响应
`res` 对象表示 Express 应用程序在接收到 HTTP 请求时发送的 HTTP 响应。
在本文档中,按照惯例,该对象始终被称为 `res`(而 HTTP 请求为 `req`),但其实际名称由你正在使用的回调函数的参数决定。
例如
app.get('/user/:id', (req, res) => {
res.send(`user ${req.params.id}`)
})
但您也可以有
app.get('/user/:id', (request, response) => {
response.send(`user ${request.params.id}`)
})
`res` 对象是 Node 自身响应对象的增强版本,支持所有内置字段和方法。
属性
res.app
此属性引用正在使用该中间件的 Express 应用程序实例。
`res.app` 与请求对象中的 req.app 属性相同。
res.headersSent
布尔属性,指示应用程序是否已为响应发送了 HTTP 头部。
app.get('/', (req, res) => {
console.log(res.headersSent) // false
res.send('OK')
console.log(res.headersSent) // true
})
res.locals
使用此属性设置可通过 res.render 渲染的模板中访问的变量。在 `res.locals` 上设置的变量在一个请求-响应周期内可用,并且不会在请求之间共享。
locals
对象由视图引擎用于渲染响应。对象键可能特别敏感,不应包含用户控制的输入,因为它可能影响视图引擎的操作或导致跨站脚本攻击。
为了在请求之间保留用于模板渲染的局部变量,请改用 app.locals。
此属性可用于将请求级别的信息(例如请求路径名、已验证用户、用户设置等)公开给应用程序内渲染的模板。
app.use((req, res, next) => {
// Make `user` and `authenticated` available in templates
res.locals.user = req.user
res.locals.authenticated = !req.user.anonymous
next()
})
res.req
此属性保存了对与此响应对象相关的请求对象的引用。
方法
res.append(field [, value])
`res.append()` 受到 Express v4.11.0+ 的支持。
将指定的 `value` 附加到 HTTP 响应头部 `field`。如果头部尚未设置,则使用指定的值创建该头部。`value` 参数可以是字符串或数组。
注意
在 `res.append()` 之后调用 `res.set()` 将会重置之前设置的头部值。
res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>'])
res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly')
res.append('Warning', '199 Miscellaneous warning')
res.attachment([filename])
将 HTTP 响应 `Content-Disposition` 头部字段设置为“attachment”。如果提供了 `filename`,则通过 `res.type()` 根据扩展名设置 `Content-Type`,并设置 `Content-Disposition` 的“filename=”参数。
res.attachment()
// Content-Disposition: attachment
res.attachment('path/to/logo.png')
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png
res.cookie(name, value [, options])
将 cookie `name` 设置为 `value`。`value` 参数可以是字符串或转换为 JSON 的对象。
`options` 参数是一个对象,可以具有以下属性。
属性 | 类型 | 描述 |
---|---|---|
domain |
字符串 | Cookie 的域名。默认为应用程序的域名。 |
encode |
函数 | 用于 cookie 值编码的同步函数。默认为 `encodeURIComponent`。 |
expires |
Date | Cookie 的 GMT 过期日期。如果未指定或设置为 0,则创建会话 cookie。 |
httpOnly |
布尔值 | 将 cookie 标记为仅能由网络服务器访问。 |
maxAge |
数字 | 方便地设置相对于当前时间的毫秒级过期时间的选项。 |
path |
字符串 | Cookie 的路径。默认为“/”。 |
partitioned |
布尔值 | 指示 cookie 应使用分区存储。有关详细信息,请参阅具有独立分区状态的 Cookie (CHIPS)。 |
priority |
字符串 | “Priority” Set-Cookie 属性的值。 |
secure |
布尔值 | 将 cookie 标记为仅与 HTTPS 一起使用。 |
signed |
布尔值 | 指示 cookie 是否应被签名。 |
sameSite |
Boolean 或 String | “SameSite” Set-Cookie 属性的值。更多信息请参见 https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1。 |
`res.cookie()` 所做的全部工作是使用提供的选项设置 HTTP `Set-Cookie` 头部。任何未指定的选项都将默认为 RFC 6265 中声明的值。
例如
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true })
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })
你可以通过多次调用 `res.cookie` 在一个响应中设置多个 cookie,例如
res
.status(201)
.cookie('access_token', `Bearer ${token}`, {
expires: new Date(Date.now() + 8 * 3600000) // cookie will be removed after 8 hours
})
.cookie('test', 'test')
.redirect(301, '/admin')
`encode` 选项允许你选择用于 cookie 值编码的函数。不支持异步函数。
示例用例:你需要为组织中的另一个站点设置一个域范围的 cookie。该站点(不在你的管理控制之下)不使用 URI 编码的 cookie 值。
// Default encoding
res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com' })
// Result: 'some_cross_domain_cookie=http%3A%2F%2Fmysubdomain.example.com; Domain=example.com; Path=/'
// Custom encoding
res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com', encode: String })
// Result: 'some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/;'
`maxAge` 选项是一个方便的选项,用于设置相对于当前时间的毫秒级“expires”。以下与上面的第二个示例等效。
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
你可以将一个对象作为 `value` 参数传递;它随后会被序列化为 JSON 并由 `bodyParser()` 中间件解析。
res.cookie('cart', { items: [1, 2, 3] })
res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 })
使用 cookie-parser 中间件时,此方法还支持签名 cookie。只需将 `signed` 选项设置为 `true`。然后,`res.cookie()` 将使用传递给 `cookieParser(secret)` 的密钥对值进行签名。
res.cookie('name', 'tobi', { signed: true })
之后,你可以通过 req.signedCookies 对象访问此值。
res.clearCookie(name [, options])
清除由 `name` 指定的 cookie。有关 `options` 对象的详细信息,请参阅 res.cookie()。
Web 浏览器和其他兼容客户端只有在给定 `options` 与提供给 res.cookie() 的选项(不包括 `expires` 和 `maxAge`)相同时才会清除 cookie。
res.cookie('name', 'tobi', { path: '/admin' })
res.clearCookie('name', { path: '/admin' })
res.download(path [, filename] [, options] [, fn])
可选的 `options` 参数从 Express v4.16.0 起受支持。
以“附件”形式传输 `path` 处的文件。通常,浏览器会提示用户下载。默认情况下,`Content-Disposition` 头部中的“filename=”参数是从 `path` 参数派生而来,但可以使用 `filename` 参数覆盖。如果 `path` 是相对路径,则它将基于进程的当前工作目录或提供的 `root` 选项。
此 API 提供对正在运行的文件系统上数据的访问。请确保 (a) 如果 `path` 参数包含用户输入,则其构造方式是安全的,或者 (b) 将 `root` 选项设置为目录的绝对路径,以限制访问范围。
当提供 `root` 选项时,Express 将验证作为 `path` 提供的相对路径是否将在给定的 `root` 选项内解析。
下表提供了 `options` 参数的详细信息。
可选的 `options` 参数从 Express v4.16.0 起受支持。
属性 | 描述 | 默认值 | 可用性 |
---|---|---|---|
maxAge |
以毫秒或 ms 格式的字符串设置 `Cache-Control` 头部中的 max-age 属性 | 0 | 4.16+ |
root |
相对文件名的根目录。 | 4.18+ | |
lastModified |
将 `Last-Modified` 头部设置为文件在操作系统上的最后修改日期。设置为 `false` 可禁用。 | 已启用 | 4.16+ |
headers |
包含要随文件发送的 HTTP 头部对象。`Content-Disposition` 头部将被 `filename` 参数覆盖。 | 4.16+ | |
dotfiles |
用于提供点文件的选项。可能的值为“allow”、“deny”、“ignore”。 | “ignore” | 4.16+ |
acceptRanges |
启用或禁用接受范围请求。 | true |
4.16+ |
cacheControl |
启用或禁用设置 `Cache-Control` 响应头部。 | true |
4.16+ |
immutable |
启用或禁用 Cache-Control 响应头中的 immutable 指令。如果启用,还应指定 maxAge 选项以启用缓存。immutable 指令将阻止受支持的客户端在 maxAge 选项的生命周期内发出条件请求,以检查文件是否已更改。 |
false |
4.16+ |
当传输完成或发生错误时,该方法会调用回调函数 `fn(err)`。如果指定了回调函数并且发生错误,回调函数必须明确处理响应过程,方法是结束请求-响应周期,或将控制权传递给下一个路由。
res.download('/report-12345.pdf')
res.download('/report-12345.pdf', 'report.pdf')
res.download('/report-12345.pdf', 'report.pdf', (err) => {
if (err) {
// Handle error, but keep in mind the response may be partially-sent
// so check res.headersSent
} else {
// decrement a download credit, etc.
}
})
res.end([data[, encoding]][, callback])
结束响应过程。此方法实际上来自 Node 核心,具体而言是 http.ServerResponse 的 response.end() 方法。
用于快速结束响应而不发送任何数据。如果需要用数据进行响应,请改用 res.send() 和 res.json() 等方法。
res.end()
res.status(404).end()
res.format(object)
当请求对象上存在 `Accept` HTTP 头部时,对其执行内容协商。它使用 req.accepts() 根据可接受类型按其质量值排序来选择请求的处理程序。如果未指定头部,则调用第一个回调。如果找不到匹配项,服务器会以 406“Not Acceptable”响应,或调用 `default` 回调。
当选择回调时,会设置 `Content-Type` 响应头部。但是,你可以在回调中使用 `res.set()` 或 `res.type()` 等方法来更改此设置。
当 `Accept` 头部字段设置为“application/json”或“*/json”时,以下示例将响应 `{ "message": "hey" }`(但是,如果它是“*/*”,则响应将是“hey”)。
res.format({
'text/plain' () {
res.send('hey')
},
'text/html' () {
res.send('<p>hey</p>')
},
'application/json' () {
res.send({ message: 'hey' })
},
default () {
// log the request and respond with 406
res.status(406).send('Not Acceptable')
}
})
除了规范化的 MIME 类型外,你还可以使用映射到这些类型的扩展名,以实现稍微简洁的实现。
res.format({
text () {
res.send('hey')
},
html () {
res.send('<p>hey</p>')
},
json () {
res.send({ message: 'hey' })
}
})
res.get(field)
返回由 `field` 指定的 HTTP 响应头部。匹配不区分大小写。
res.get('Content-Type')
// => "text/plain"
res.json([body])
发送 JSON 响应。此方法发送一个响应(带有正确的内容类型),该响应是使用 JSON.stringify() 将参数转换为 JSON 字符串后的结果。
参数可以是任何 JSON 类型,包括对象、数组、字符串、布尔值、数字或 null,你也可以用它来将其他值转换为 JSON。
res.json(null)
res.json({ user: 'tobi' })
res.status(500).json({ error: 'message' })
res.jsonp([body])
发送带有 JSONP 支持的 JSON 响应。此方法与 `res.json()` 相同,不同之处在于它选择了 JSONP 回调支持。
res.jsonp(null)
// => callback(null)
res.jsonp({ user: 'tobi' })
// => callback({ "user": "tobi" })
res.status(500).jsonp({ error: 'message' })
// => callback({ "error": "message" })
默认情况下,JSONP 回调名称仅为 `callback`。使用 jsonp callback name 设置覆盖它。
以下是使用相同代码的一些 JSONP 响应示例:
// ?callback=foo
res.jsonp({ user: 'tobi' })
// => foo({ "user": "tobi" })
app.set('jsonp callback name', 'cb')
// ?cb=foo
res.status(500).jsonp({ error: 'message' })
// => foo({ "error": "message" })
res.links(links)
将作为参数属性提供的 `links` 连接起来,以填充响应的 `Link` HTTP 头部字段。
例如,以下调用:
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
})
产生以下结果:
Link: <http://api.example.com/users?page=2>; rel="next",
<http://api.example.com/users?page=5>; rel="last"
res.location(path)
将响应 `Location` HTTP 头部设置为指定的 `path` 参数。
res.location('/foo/bar')
res.location('http://example.com')
在对 URL 进行编码后(如果尚未编码),Express 会将指定的 URL 传递给浏览器在 `Location` 头部中,不进行任何验证。
浏览器负责从当前 URL 或引用 URL 以及 `Location` 头部中指定的 URL 推导出目标 URL;并相应地重定向用户。
res.redirect([status,] path)
重定向到从指定 `path` 派生的 URL,并带有指定的 `status`(一个对应于 HTTP 状态码的正整数)。如果未指定,`status` 默认为 `302 "Found"`。
res.redirect('/foo/bar')
res.redirect('http://example.com')
res.redirect(301, 'http://example.com')
res.redirect('../login')
重定向可以是用于重定向到不同站点的完全限定 URL。
res.redirect('http://google.com')
重定向可以是相对于主机名根目录的。例如,如果应用程序位于 `http://example.com/admin/post/new`,以下将重定向到 URL `http://example.com/admin`:
res.redirect('/admin')
重定向可以是相对于当前 URL 的。例如,从 `http://example.com/blog/admin/`(注意尾部斜杠),以下将重定向到 URL `http://example.com/blog/admin/post/new`。
res.redirect('post/new')
从 `http://example.com/blog/admin`(无尾部斜杠)重定向到 `post/new`,将重定向到 `http://example.com/blog/post/new`。
如果你觉得上述行为令人困惑,请将路径段视为目录(带尾部斜杠)和文件,这样就会开始理解了。
路径相对重定向也是可能的。如果你位于 `http://example.com/admin/post/new`,以下将重定向到 `http://example.com/admin/post`:
res.redirect('..')
另请参见安全最佳实践:防止开放重定向漏洞。
res.render(view [, locals] [, callback])
渲染一个 `view` 并将渲染后的 HTML 字符串发送给客户端。可选参数:
- `locals`,一个对象,其属性为视图定义局部变量。
- `callback`,一个回调函数。如果提供,该方法将返回可能的错误和渲染后的字符串,但不会执行自动响应。当发生错误时,该方法会在内部调用 `next(err)`。
`view` 参数是一个字符串,表示要渲染的视图文件的文件路径。这可以是绝对路径,也可以是相对于 `views` 设置的路径。如果路径不包含文件扩展名,则由 `view engine` 设置确定文件扩展名。如果路径包含文件扩展名,则 Express 将加载指定模板引擎的模块(通过 `require()`),并使用加载模块的 `__express` 函数进行渲染。
欲了解更多信息,请参阅在 Express 中使用模板引擎。
警告
view
参数执行文件系统操作,例如从磁盘读取文件和评估 Node.js 模块,因此出于安全原因,不应包含来自最终用户的输入。
警告
locals
对象由视图引擎用于渲染响应。对象键可能特别敏感,不应包含用户控制的输入,因为它可能影响视图引擎的操作或导致跨站脚本攻击。
注意
局部变量 `cache` 启用视图缓存。将其设置为 `true`,以便在开发期间缓存视图;视图缓存在生产环境中默认启用。
// send the rendered view to the client
res.render('index')
// if a callback is specified, the rendered HTML string has to be sent explicitly
res.render('index', (err, html) => {
res.send(html)
})
// pass a local variable to the view
res.render('user', { name: 'Tobi' }, (err, html) => {
// ...
})
res.send([body])
发送 HTTP 响应。
`body` 参数可以是 `Buffer` 对象、`String`、对象、`Boolean` 或 `Array`。例如
res.send(Buffer.from('whoop'))
res.send({ some: 'json' })
res.send('<p>some html</p>')
res.status(404).send('Sorry, we cannot find that!')
res.status(500).send({ error: 'something blew up' })
此方法为简单的非流式响应执行许多有用的任务:例如,它会自动分配 `Content-Length` HTTP 响应头部字段,并提供自动 HEAD 和 HTTP 缓存新鲜度支持。
当参数是 `Buffer` 对象时,该方法将 `Content-Type` 响应头部字段设置为“application/octet-stream”,除非之前已定义,如下所示:
res.set('Content-Type', 'text/html')
res.send(Buffer.from('<p>some html</p>'))
当参数是 `String` 时,该方法将 `Content-Type` 设置为“text/html”。
res.send('<p>some html</p>')
当参数是 `Array` 或 `Object` 时,Express 将以 JSON 表示形式响应:
res.send({ user: 'tobi' })
res.send([1, 2, 3])
res.sendFile(path [, options] [, fn])
`res.sendFile()` 受到 Express v4.8.0 及更高版本的支持。
传输给定 `path` 处的文件。根据文件名的扩展名设置 `Content-Type` 响应 HTTP 头部字段。除非在 options 对象中设置了 `root` 选项,否则 `path` 必须是文件的绝对路径。
此 API 提供对正在运行的文件系统上数据的访问。请确保 (a) 如果 `path` 参数包含用户输入,则其构造为绝对路径的方式是安全的,或者 (b) 将 `root` 选项设置为目录的绝对路径,以限制访问范围。
当提供 `root` 选项时,`path` 参数允许是相对路径,包括包含 `..`。Express 将验证作为 `path` 提供的相对路径是否将在给定的 `root` 选项内解析。
下表提供了 `options` 参数的详细信息。
属性 | 描述 | 默认值 | 可用性 |
---|---|---|---|
maxAge |
以毫秒或 ms 格式的字符串设置 `Cache-Control` 头部中的 max-age 属性 | 0 | |
root |
相对文件名的根目录。 | ||
lastModified |
将 `Last-Modified` 头部设置为文件在操作系统上的最后修改日期。设置为 `false` 可禁用。 | 已启用 | 4.9.0+ |
headers |
包含要随文件发送的 HTTP 头部对象。 | ||
dotfiles |
用于提供点文件的选项。可能的值为“allow”、“deny”、“ignore”。 | “ignore” | |
acceptRanges |
启用或禁用接受范围请求。 | true |
4.14+ |
cacheControl |
启用或禁用设置 `Cache-Control` 响应头部。 | true |
4.14+ |
immutable |
启用或禁用 Cache-Control 响应头中的 immutable 指令。如果启用,还应指定 maxAge 选项以启用缓存。immutable 指令将阻止受支持的客户端在 maxAge 选项的生命周期内发出条件请求,以检查文件是否已更改。 |
false |
4.16+ |
当传输完成或发生错误时,该方法会调用回调函数 `fn(err)`。如果指定了回调函数并且发生错误,回调函数必须明确处理响应过程,方法是结束请求-响应周期,或将控制权传递给下一个路由。
以下是 `res.sendFile` 及其所有参数的使用示例。
app.get('/file/:name', (req, res, next) => {
const options = {
root: path.join(__dirname, 'public'),
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
}
const fileName = req.params.name
res.sendFile(fileName, options, (err) => {
if (err) {
next(err)
} else {
console.log('Sent:', fileName)
}
})
})
以下示例说明了如何使用 `res.sendFile` 提供对文件服务的精细支持:
app.get('/user/:uid/photos/:file', (req, res) => {
const uid = req.params.uid
const file = req.params.file
req.user.mayViewFilesFrom(uid, (yes) => {
if (yes) {
res.sendFile(`/uploads/${uid}/${file}`)
} else {
res.status(403).send("Sorry! You can't see that.")
}
})
})
如需了解更多信息,或遇到问题,请参阅 send。
res.sendStatus(statusCode)
将响应 HTTP 状态码设置为 `statusCode`,并将注册的状态消息作为文本响应正文发送。如果指定了未知状态码,响应正文将仅为代码编号。
res.sendStatus(404)
某些版本的 Node.js 在 `res.statusCode` 设置为无效 HTTP 状态码(超出 `100` 到 `599` 的范围)时会抛出错误。请查阅正在使用的 Node.js 版本的 HTTP 服务器文档。
res.set(field [, value])
将响应的 HTTP 头部 `field` 设置为 `value`。要一次设置多个字段,请传递一个对象作为参数。
res.set('Content-Type', 'text/plain')
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
ETag: '12345'
})
别名为 `res.header(field [, value])`。
res.status(code)
设置响应的 HTTP 状态。它是 Node 的 response.statusCode 的链式别名。
res.status(403).end()
res.status(400).send('Bad Request')
res.status(404).sendFile('/absolute/path/to/404.png')
res.type(type)
将 `Content-Type` HTTP 头部设置为由指定的 `type` 确定的 MIME 类型。如果 `type` 包含“/”字符,则将 `Content-Type` 设置为 `type` 的确切值,否则假定为文件扩展名,并使用 `mime-types` 包的 `contentType()` 方法查找 MIME 类型。
res.type('.html') // => 'text/html'
res.type('html') // => 'text/html'
res.type('json') // => 'application/json'
res.type('application/json') // => 'application/json'
res.type('png') // => image/png:
别名为 `res.contentType(type)`。
res.vary(field)
将 `field` 添加到 `Vary` 响应头部,如果它尚不存在。
res.vary('User-Agent').render('docs')
路由
`router` 对象是中间件和路由的一个实例。你可以将其视为一个“迷你应用程序”,它只能执行中间件和路由功能。每个 Express 应用程序都有一个内置的应用程序路由器。
路由器本身的行为类似于中间件,因此你可以将其用作 app.use() 的参数,或作为另一个路由器的 use() 方法的参数。
顶层 `express` 对象具有一个 Router() 方法,该方法会创建一个新的 `router` 对象。
创建路由器对象后,你可以像应用程序一样向其添加中间件和 HTTP 方法路由(例如 `get`、`put`、`post` 等)。例如
// invoked for any requests passed to this router
router.use((req, res, next) => {
// .. some logic here .. like any other middleware
next()
})
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', (req, res, next) => {
// ..
})
然后,你可以以这种方式为特定的根 URL 使用路由器,将路由分离到文件中,甚至分离到迷你应用程序中。
// only requests to /calendar/* will be sent to our "router"
app.use('/calendar', router)
请记住,应用于路由器的任何中间件都将运行在该路由器路径上的所有请求,即使这些请求不属于该路由器。
方法
router.all(path, [callback, ...] callback)
此方法与 `router.METHOD()` 方法类似,不同之处在于它匹配所有 HTTP 方法(动词)。
此方法对于为特定路径前缀或任意匹配映射“全局”逻辑非常有用。例如,如果你将以下路由放在所有其他路由定义的最顶部,那么从该点开始的所有路由都将需要身份验证,并自动加载用户。请记住,这些回调不必充当端点;`loadUser` 可以执行任务,然后调用 `next()` 以继续匹配后续路由。
router.all('{*splat}', requireAuthentication, loadUser)
或等效代码
router.all('{*splat}', requireAuthentication)
router.all('{*splat}', loadUser)
另一个例子是白名单化的“全局”功能。这里,示例与之前非常相似,但它只限制以“/api”为前缀的路径:
router.all('/api/{*splat}', requireAuthentication)
router.METHOD(path, [callback, ...] callback)
`router.METHOD()` 方法在 Express 中提供路由功能,其中 METHOD 是 HTTP 方法之一,例如 GET、PUT、POST 等(小写)。因此,实际方法是 `router.get()`、`router.post()`、`router.put()` 等。
如果在调用 `router.get()` 之前没有为该路径调用 `router.head()`,则除了 `GET` 方法外,`router.get()` 函数也会自动为 HTTP `HEAD` 方法调用。
你可以提供多个回调,它们都将被平等对待,并且行为与中间件类似,不同之处在于这些回调可以调用 `next('route')` 来绕过剩余的路由回调。你可以使用这种机制对路由执行预处理,然后在没有理由继续匹配当前路由时将控制权传递给后续路由。
以下代码片段展示了最简单的路由定义。Express 将路径字符串转换为正则表达式,并在内部用于匹配传入请求。在执行这些匹配时,*不*考虑查询字符串,例如“GET /”将匹配以下路由,“GET /?name=tobi”也会匹配。
router.get('/', (req, res) => {
res.send('hello world')
})
你也可以使用正则表达式——如果你有非常具体的约束,这会很有用,例如以下内容将匹配“GET /commits/71dbb9c”以及“GET /commits/71dbb9c..4c084f9”。
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, (req, res) => {
const from = req.params[0]
const to = req.params[1] || 'HEAD'
res.send(`commit range ${from}..${to}`)
})
你可以使用 `next` 原语根据特定的程序状态在不同的中间件函数之间实现流程控制。使用字符串 `'router'` 调用 `next` 将导致该路由器上所有剩余的路由回调被绕过。
以下示例说明了 `next('router')` 的用法。
function fn (req, res, next) {
console.log('I come here')
next('router')
}
router.get('/foo', fn, (req, res, next) => {
console.log('I dont come here')
})
router.get('/foo', (req, res, next) => {
console.log('I dont come here')
})
app.get('/foo', (req, res) => {
console.log(' I come here too')
res.end('good')
})
router.param(name, callback)
为路由参数添加回调触发器,其中 `name` 是参数的名称,`callback` 是回调函数。尽管 `name` 在技术上是可选的,但从 Express v4.11.0 开始,不带它的此方法已被弃用(参见下文)。
回调函数的参数为:
- `req`,请求对象。
- `res`,响应对象。
- `next`,表示下一个中间件函数。
- `name` 参数的值。
- 参数的名称。
与 `app.param()` 不同,`router.param()` 不接受路由参数数组。
例如,当路由路径中存在 :user
时,您可以映射用户加载逻辑以自动向路由提供 req.user
,或对参数输入执行验证。
router.param('user', (req, res, next, id) => {
// try to get the user details from the User model and attach it to the request object
User.find(id, (err, user) => {
if (err) {
next(err)
} else if (user) {
req.user = user
next()
} else {
next(new Error('failed to load user'))
}
})
})
参数回调函数是定义它们的路由器的本地函数。它们不会被挂载的应用程序或路由器继承,也不会因从父路由器继承的路由参数而触发。因此,在 `router` 上定义的参数回调仅由在 `router` 路由上定义的路由参数触发。
参数回调在请求-响应周期中只会调用一次,即使参数在多个路由中匹配,如下例所示。
router.param('id', (req, res, next, id) => {
console.log('CALLED ONLY ONCE')
next()
})
router.get('/user/:id', (req, res, next) => {
console.log('although this matches')
next()
})
router.get('/user/:id', (req, res) => {
console.log('and this matches too')
res.end()
})
在 GET /user/42
上,打印以下内容
CALLED ONLY ONCE
although this matches
and this matches too
router.route(path)
返回单个路由的实例,你可以使用它来处理带有可选中间件的 HTTP 动词。使用 `router.route()` 可以避免重复的路由命名和因此产生的输入错误。
在上面的 `router.param()` 示例的基础上,以下代码展示了如何使用 `router.route()` 来指定各种 HTTP 方法处理程序。
const router = express.Router()
router.param('user_id', (req, res, next, id) => {
// sample user, would actually fetch from DB, etc...
req.user = {
id,
name: 'TJ'
}
next()
})
router.route('/users/:user_id')
.all((req, res, next) => {
// runs for all HTTP verbs first
// think of it as route specific middleware!
next()
})
.get((req, res, next) => {
res.json(req.user)
})
.put((req, res, next) => {
// just an example of maybe updating the user
req.user.name = req.params.name
// save user ... etc
res.json(req.user)
})
.post((req, res, next) => {
next(new Error('not implemented'))
})
.delete((req, res, next) => {
next(new Error('not implemented'))
})
这种方法复用单个 `/users/:user_id` 路径,并为各种 HTTP 方法添加处理程序。
注意
当你使用 `router.route()` 时,中间件的排序是基于路由创建的时间,而不是方法处理程序添加到路由的时间。为此,你可以认为方法处理程序属于它们被添加到的路由。
router.use([path], [function, ...] function)
使用指定的中间件函数(或多个函数),带有可选的挂载路径 `path`,默认为“/”。
此方法类似于 app.use()。下面将描述一个简单的示例和用例。有关更多信息,请参阅 app.use()。
中间件就像一个管道:请求从定义的第一个中间件函数开始,然后“向下”遍历中间件堆栈,处理它们匹配的每个路径。
const express = require('express')
const app = express()
const router = express.Router()
// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use((req, res, next) => {
console.log('%s %s %s', req.method, req.url, req.path)
next()
})
// this will only be invoked if the path starts with /bar from the mount point
router.use('/bar', (req, res, next) => {
// ... maybe some additional /bar logging ...
next()
})
// always invoked
router.use((req, res, next) => {
res.send('Hello World')
})
app.use('/foo', router)
app.listen(3000)
“挂载”路径会被剥离,并且对于中间件函数是不可见的。此功能的主要作用是,挂载的中间件函数可以无需更改代码即可运行,无论其“前缀”路径名是什么。
使用 `router.use()` 定义中间件的顺序非常重要。它们是按顺序调用的,因此顺序决定了中间件的优先级。例如,通常日志记录器是你使用的第一个中间件,以便每个请求都得到记录。
const logger = require('morgan')
router.use(logger())
router.use(express.static(path.join(__dirname, 'public')))
router.use((req, res) => {
res.send('Hello')
})
现在假设你想要忽略对静态文件的日志记录请求,但继续记录在 `logger()` 之后定义的路由和中间件。你只需将 `express.static()` 的调用移到顶部,在添加日志记录中间件之前:
router.use(express.static(path.join(__dirname, 'public')))
router.use(logger())
router.use((req, res) => {
res.send('Hello')
})
另一个例子是从多个目录提供文件,其中“./public”优先于其他目录:
app.use(express.static(path.join(__dirname, 'public')))
app.use(express.static(path.join(__dirname, 'files')))
app.use(express.static(path.join(__dirname, 'uploads')))
`router.use()` 方法还支持命名参数,这样你为其他路由器设置的挂载点可以受益于使用命名参数进行预加载。
注意:尽管这些中间件函数是通过特定路由器添加的,但它们运行的*时间*是由它们所附加的路径(而不是路由器)定义的。因此,如果路由匹配,通过一个路由器添加的中间件也可能为其他路由器运行。例如,此代码显示了两个不同的路由器挂载在同一路径上:
const authRouter = express.Router()
const openRouter = express.Router()
authRouter.use(require('./authenticate').basic(usersdb))
authRouter.get('/:user_id/edit', (req, res, next) => {
// ... Edit user UI ...
})
openRouter.get('/', (req, res, next) => {
// ... List users ...
})
openRouter.get('/:user_id', (req, res, next) => {
// ... View user ...
})
app.use('/users', authRouter)
app.use('/users', openRouter)
即使身份验证中间件是通过 `authRouter` 添加的,它也会在 `openRouter` 定义的路由上运行,因为两个路由器都挂载在 `/users` 上。为避免此行为,请为每个路由器使用不同的路径。