黑人的命也是命。
支持平权倡议组织.

4.x API

express()

创建 Express 应用程序。express() 函数是 express 模块导出的顶级函数。

var express = require('express')
var app = express()

方法

express.json([options])

此中间件从 Express v4.16.0 开始可用。

这是 Express 中的内置中间件函数。它解析具有 JSON 负载的传入请求,并基于 body-parser

返回仅解析 JSON 且仅查看 Content-Type 标头与 type 选项匹配的请求的中间件。此解析器接受正文的任何 Unicode 编码,并支持 gzipdeflate 编码的自动膨胀。

在中间件之后,在 request 对象上填充一个包含解析数据的新的 body 对象(即 req.body),或者如果没有任何正文要解析,Content-Type 未匹配或发生错误,则填充一个空对象 ({})。

由于 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 v4.17.0 及更高版本中可用。

这是 Express 中的内置中间件函数。它将传入的请求有效负载解析为 Buffer,并且基于 body-parser

返回一个中间件,该中间件将所有正文解析为 Buffer,并且仅查看 Content-Type 标头与 type 选项匹配的请求。此解析器接受正文的任何 Unicode 编码,并支持自动膨胀 gzipdeflate 编码。

在中间件之后(即 req.body)在 request 对象上填充一个包含解析数据的新的 body Buffer,或者如果没有任何正文要解析,Content-Type 未匹配或发生错误,则填充一个空对象 ({})。

由于 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])

创建一个新的 路由器 对象。

var router = express.Router([options])

可选的 options 参数指定路由器的行为。

属性 描述 默认值 可用性
caseSensitive 启用区分大小写。 默认情况下禁用,将“/Foo”和“/foo”视为相同。  
mergeParams 保留来自父路由器的 req.params 值。如果父级和子级具有冲突的参数名称,则子级的值优先。 false 4.5.0+
strict 启用严格路由。 默认情况下禁用,“/foo”和“/foo/”由路由器视为相同。  

您可以向 router 添加中间件和 HTTP 方法路由(例如 getputpost 等),就像应用程序一样。

有关更多信息,请参见 路由器

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 让客户端错误作为未处理的请求继续,否则转发客户端错误。

参见下面的 fallthrough
布尔值 true
immutable Cache-Control 响应头中启用或禁用 immutable 指令。如果启用,还应指定 maxAge 选项以启用缓存。immutable 指令将阻止支持的客户端在 maxAge 选项的生命周期内发出条件请求以检查文件是否已更改。 布尔值 false
索引 发送指定的目录索引文件。设置为 false 以禁用目录索引。 混合 “index.html”
最后修改时间 Last-Modified 头设置为文件在操作系统上的最后修改日期。 布尔值 true
最大年龄 以毫秒或 ms 格式 的字符串设置 Cache-Control 头的 max-age 属性。 数字 0
重定向 当路径名是目录时,重定向到尾部的“/”。 布尔值 true
设置头 用于设置与文件一起提供的 HTTP 头的函数。

参见下面的 setHeaders
函数  

有关更多信息,请参见 在 Express 中提供静态文件使用中间件 - 内置中间件

dotfiles

此选项的可能值为

  • “允许” - 对点文件没有特殊处理。
  • “拒绝” - 拒绝对点文件的请求,以 403 响应,然后调用 next()
  • “忽略” - 就像点文件不存在一样,以 404 响应,然后调用 next()

注意:使用默认值,它不会忽略以点开头的目录中的文件。

fallthrough

当此选项为 true 时,客户端错误(例如错误请求或对不存在文件的请求)将导致此中间件简单地调用 next() 以调用堆栈中的下一个中间件。当为 false 时,这些错误(即使是 404),将调用 next(err)

将此选项设置为 true,以便您可以将多个物理目录映射到同一个 Web 地址,或者让路由填充不存在的文件。

如果您已将此中间件安装在设计为严格的单个文件系统目录的路径上,请使用 false,这允许为更少的开销短路 404。此中间件也将回复所有方法。

设置头

对于此选项,请指定一个函数来设置自定义响应头。对头的更改必须同步发生。

函数的签名是

fn(res, path, stat)

参数

  • res响应对象
  • path,正在发送的文件路径。
  • stat,正在发送的文件的 stat 对象。

express.static 的示例

以下是如何使用带有详细选项对象的 express.static 中间件函数的示例

var options = {
  dotfiles: 'ignore',
  etag: false,
  extensions: ['htm', 'html'],
  index: false,
  maxAge: '1d',
  redirect: false,
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now())
  }
}

app.use(express.static('public', options))

express.text([options])

此中间件在 Express v4.17.0 及更高版本中可用。

这是 Express 中的内置中间件函数。它将传入的请求有效负载解析为字符串,并基于 body-parser

返回一个中间件,它将所有主体解析为字符串,并且只查看 Content-Type 标头与 type 选项匹配的请求。此解析器接受主体的任何 Unicode 编码,并支持自动膨胀 gzipdeflate 编码。

在中间件之后(即 req.body),在 request 对象上填充一个包含解析数据的新的 body 字符串,或者如果没有任何主体要解析,Content-Type 未匹配或发生错误,则填充一个空对象 ({})。

由于 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 v4.16.0 开始可用。

这是 Express 中的内置中间件函数。它解析具有 urlencoded 有效负载的传入请求,并基于 body-parser

返回一个中间件,它只解析 urlencoded 主体,并且只查看 Content-Type 标头与 type 选项匹配的请求。此解析器只接受主体的 UTF-8 编码,并支持自动膨胀 gzipdeflate 编码。

在中间件之后(即 req.body),request 对象上会填充一个包含解析数据的新的 body 对象,如果解析没有主体,Content-Type 不匹配或发生错误,则填充一个空对象 ({})。此对象将包含键值对,其中值可以是字符串或数组(当 extendedfalse 时),或任何类型(当 extendedtrue 时)。

由于 req.body 的形状基于用户控制的输入,因此此对象中的所有属性和值都是不可信的,应在信任之前进行验证。例如,req.body.foo.toString() 可能以多种方式失败,例如 foo 可能不存在或可能不是字符串,并且 toString 可能不是函数,而是字符串或其他用户输入。

下表描述了可选 options 对象的属性。

属性 描述 类型 默认值
extended 此选项允许在使用 querystring 库(当 false 时)或 qs 库(当 true 时)解析 URL 编码数据之间进行选择。“扩展”语法允许将丰富的对象和数组编码为 URL 编码格式,从而允许使用 URL 编码实现类似 JSON 的体验。有关更多信息,请 查看 qs 库 布尔值 true
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() 函数来创建它。

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('hello world')
})

app.listen(3000)

app 对象具有用于以下目的的方法:

它还具有影响应用程序行为的设置(属性);有关更多信息,请参阅 应用程序设置

Express 应用程序对象可以通过 请求对象响应对象 访问,分别为 req.appres.app

属性

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 的一个实例,可用于处理对路由的请求。

var express = require('express')

var app = express() // the main app
var admin = express() // the sub app

admin.get('/', function (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 将返回它安装的模式列表,如下例所示。

var admin = express()

admin.get('/', function (req, res) {
  console.dir(admin.mountpath) // [ '/adm*n', '/manager' ]
  res.send('Admin Homepage')
})

var secret = express()
secret.get('/', function (req, res) {
  console.log(secret.mountpath) // /secr*t
  res.send('Admin Secret')
})

admin.use('/secr*t', secret) // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin) // load the 'admin' router on '/adm*n' and '/manager', on the parent app

事件

app.on('mount', callback(parent))

当子应用程序安装在父应用程序上时,mount 事件将在子应用程序上触发。父应用程序将传递给回调函数。

注意

子应用程序将

  • 不继承具有默认值的设置的值。您必须在子应用程序中设置该值。
  • 继承没有默认值的设置的值。

有关详细信息,请参阅 应用程序设置

var admin = express()

admin.on('mount', function (parent) {
  console.log('Admin Mounted')
  console.log(parent) // refers to the parent app
})

admin.get('/', function (req, res) {
  res.send('Admin Homepage')
})

app.use('/admin', admin)

方法

app.all(path, callback [, callback ...])

此方法类似于标准的 app.METHOD() 方法,不同之处在于它匹配所有 HTTP 动词。

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

示例

以下回调将对 /secret 的请求执行,无论使用 GET、POST、PUT、DELETE 还是任何其他 HTTP 请求方法

app.all('/secret', function (req, res, next) {
  console.log('Accessing the secret section ...')
  next() // pass control to the next handler
})

app.all() 方法对于为特定路径前缀或任意匹配映射“全局”逻辑很有用。例如,如果您将以下内容放在所有其他路由定义的顶部,它将要求从该点开始的所有路由都需要身份验证,并自动加载用户。请记住,这些回调不必充当端点:loadUser 可以执行任务,然后调用 next() 以继续匹配后续路由。

app.all('*', requireAuthentication, loadUser)

或等效的

app.all('*', requireAuthentication)
app.all('*', loadUser)

另一个示例是白名单“全局”功能。该示例类似于上面的示例,但它只限制以“/api”开头的路径

app.all('/api/*', requireAuthentication)

app.delete(path, callback [, callback ...])

将 HTTP DELETE 请求路由到指定路径,并使用指定的回调函数。有关更多信息,请参见 路由指南

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

示例

app.delete('/', function (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 提供了一个 .renderFile() 方法,该方法具有与 Express 预期相同的签名:(path, options, callback),但请注意,它在内部将此方法别名为 ejs.__express,因此如果您使用“.ejs”扩展名,则无需执行任何操作。

一些模板引擎不遵循此约定。 consolidate.js 库将 Node 模板引擎映射到遵循此约定,因此它们可以与 Express 无缝地协同工作。

var 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 请求路由到指定路径,并使用指定的回调函数。

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

有关更多信息,请参阅 路由指南

示例

app.get('/', function (req, res) {
  res.send('GET request to homepage')
})

app.listen(path, [callback])

启动一个 UNIX 套接字,并在给定路径上监听连接。此方法与 Node 的 http.Server.listen() 相同。

var express = require('express')
var app = express()
app.listen('/tmp/sock')

app.listen([port[, host[, backlog]]][, callback])

绑定并监听指定主机和端口上的连接。此方法与 Node 的 http.Server.listen() 相同。

如果省略端口或端口为 0,操作系统将分配一个任意的未使用的端口,这对于自动化任务(测试等)很有用。

var express = require('express')
var app = express()
app.listen(3000)

express() 返回的 app 实际上是一个 JavaScript Function,旨在传递给 Node 的 HTTP 服务器作为回调来处理请求。这使得使用相同的代码库轻松提供应用程序的 HTTP 和 HTTPS 版本,因为应用程序不会继承自这些版本(它只是一个回调)。

var express = require('express')
var https = require('https')
var http = require('http')
var app = express()

http.createServer(app).listen(80)
https.createServer(options, app).listen(443)

app.listen() 方法返回一个 http.Server 对象,并且(对于 HTTP)是以下内容的便捷方法

app.listen = function () {
  var 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() 等。有关完整列表,请参见下面的 路由方法

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

路由方法

Express 支持以下路由方法,对应于同名 HTTP 方法

  • checkout
  • copy
  • delete
  • get
  • head
  • lock
  • merge
  • mkactivity
  • mkcol
  • move
  • m-search
  • notify
  • options
  • patch
  • post
  • purge
  • put
  • report
  • search
  • subscribe
  • trace
  • unlock
  • unsubscribe

API 文档仅对最常用的 HTTP 方法 app.get()app.post()app.put()app.delete() 有明确的条目。但是,上面列出的其他方法的工作方式完全相同。

要路由转换为无效 JavaScript 变量名的方法,请使用方括号表示法。例如,app['m-search']('/', function ...

如果在 app.get() 之前没有为路径调用 app.head(),则 app.get() 函数会自动为 HTTP HEAD 方法调用,除了 GET 方法之外。

方法 app.all() 并非源自任何 HTTP 方法,并且会在指定路径上为所有 HTTP 请求方法加载中间件。有关更多信息,请参见 app.all

有关路由的更多信息,请参见 路由指南

app.param([name], callback)

路由参数 添加回调触发器,其中 name 是参数的名称或它们的数组,callback 是回调函数。回调函数的参数依次是请求对象、响应对象、下一个中间件、参数的值和参数的名称。

如果name是一个数组,则会为其中声明的每个参数注册callback触发器,注册顺序与声明顺序一致。此外,对于除最后一个参数外的每个声明参数,在回调函数中调用next将调用下一个声明参数的回调函数。对于最后一个参数,调用next将调用当前正在处理的路由的下一个中间件,就像name只是一个字符串一样。

例如,当:user出现在路由路径中时,您可以将用户加载逻辑映射到自动为路由提供req.user,或对参数输入进行验证。

app.param('user', function (req, res, next, id) {
  // try to get the user details from the User model and attach it to the request object
  User.find(id, function (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', function (req, res, next, id) {
  console.log('CALLED ONLY ONCE')
  next()
})

app.get('/user/:id', function (req, res, next) {
  console.log('although this matches')
  next()
})

app.get('/user/:id', function (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'], function (req, res, next, value) {
  console.log('CALLED ONLY ONCE with', value)
  next()
})

app.get('/user/:id/:page', function (req, res, next) {
  console.log('although this matches')
  next()
})

app.get('/user/:id/:page', function (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.param(callback),该方法在 v4.11.0 及更高版本中已弃用。

app.param(name, callback)方法的行为可以通过只向app.param()传递一个函数来完全改变。此函数是app.param(name, callback)应该如何运行的自定义实现 - 它接受两个参数,并且必须返回一个中间件。

此函数的第一个参数是应该捕获的 URL 参数的名称,第二个参数可以是任何 JavaScript 对象,它可能用于返回中间件实现。

函数返回的中间件决定了捕获 URL 参数时发生的事情的行为。

在此示例中,app.param(name, callback)签名被修改为app.param(name, accessId)app.param()现在不再接受名称和回调函数,而是接受名称和数字。

var express = require('express')
var app = express()

// customizing the behavior of app.param()
app.param(function (param, option) {
  return function (req, res, next, val) {
    if (val === option) {
      next()
    } else {
      next('route')
    }
  }
})

// using the customized app.param()
app.param('id', 1337)

// route to trigger the capture
app.get('/user/:id', function (req, res) {
  res.send('OK')
})

app.listen(3000, function () {
  console.log('Ready')
})

在此示例中,app.param(name, callback)签名保持不变,但自定义数据类型检查函数已定义为验证用户 ID 的数据类型,而不是中间件回调函数。

app.param(function (param, validator) {
  return function (req, res, next, val) {
    if (validator(val)) {
      next()
    } else {
      next('route')
    }
  }
})

app.param('id', function (candidate) {
  return !isNaN(parseFloat(candidate)) && isFinite(candidate)
})

.’ 字符不能用于在捕获正则表达式中捕获字符。例如,您不能使用'/user-.+/'来捕获'users-gami',请改用[\\s\\S][\\w\\W](如'/user-[\\s\\S]+/')。

示例

// captures '1-a_6' but not '543-azser-sder'
router.get('/[0-9]+-[[\\w]]*', function (req, res, next) { next() })

// captures '1-a_6' and '543-az(ser"-sder' but not '5-a s'
router.get('/[0-9]+-[[\\S]]*', function (req, res, next) { next() })

// captures all (equivalent to '.*')
router.get('[[\\s\\S]]*', function (req, res, next) { next() })

app.path()

返回应用程序的规范路径,一个字符串。

var app = express()
var blog = express()
var blogAdmin = express()

app.use('/blog', blog)
blog.use('/admin', blogAdmin)

console.dir(app.path()) // ''
console.dir(blog.path()) // '/blog'
console.dir(blogAdmin.path()) // '/blog/admin'

在复杂的情况下,挂载的应用程序的行为可能会变得非常复杂:通常最好使用 req.baseUrl 来获取应用程序的规范路径。

app.post(path, callback [, callback ...])

将 HTTP POST 请求路由到指定路径,并使用指定的回调函数。有关更多信息,请参阅 路由指南

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

示例

app.post('/', function (req, res) {
  res.send('POST request to homepage')
})

app.put(path, callback [, callback ...])

将 HTTP PUT 请求路由到指定路径,并使用指定的回调函数。

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

示例

app.put('/', function (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', function (err, html) {
  // ...
})

app.render('email', { name: 'Tobi' }, function (err, html) {
  // ...
})

app.route(path)

返回单个路由的实例,然后可以使用该实例来处理具有可选中间件的 HTTP 动词。使用 app.route() 来避免重复的路由名称(从而避免打字错误)。

var app = express()

app.route('/events')
  .all(function (req, res, next) {
    // runs for all HTTP verbs first
    // think of it as route specific middleware!
  })
  .get(function (req, res, next) {
    res.json({})
  })
  .post(function (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”将被视为相同。

注意:子应用程序将继承此设置的值。

N/A(未定义)

环境

字符串 环境模式。请确保在生产环境中设置为“production”;请参阅生产最佳实践:性能和可靠性

process.env.NODE_ENVNODE_ENV环境变量)或“development”(如果未设置NODE_ENV)。

etag

多种

设置ETag响应头。有关可能的值,请参阅etag选项表

有关HTTP ETag头的更多信息.

JSONP回调名称

字符串 指定默认的JSONP回调名称。

“callback”

JSON转义

布尔值

启用从res.jsonres.jsonpres.send API转义JSON响应。这将把<>&字符作为Unicode转义序列转义到JSON中。这样做是为了帮助缓解某些类型的持久性XSS攻击,当客户端嗅探HTML响应时。

注意:子应用程序将继承此设置的值。

N/A(未定义)

JSON替换器

多种 JSON.stringify使用的'replacer'参数

注意:子应用程序将继承此设置的值。

N/A(未定义)

JSON空格

多种 JSON.stringify使用的'space'参数。这通常设置为用于缩进美化JSON的空格数。

注意:子应用程序将继承此设置的值。

N/A(未定义)

查询解析器

多种

通过将值设置为false来禁用查询解析,或者将查询解析器设置为使用“simple”或“extended”或自定义查询字符串解析函数。

简单查询解析器基于Node的原生查询解析器,querystring

扩展查询解析器基于qs

自定义查询字符串解析函数将接收完整的查询字符串,并且必须返回一个包含查询键及其值的键值对对象。

"extended"

严格路由

布尔值

启用严格路由。启用后,路由器将“/foo”和“/foo/”视为不同。否则,路由器将“/foo”和“/foo/”视为相同。

注意:子应用程序将继承此设置的值。

N/A(未定义)

子域偏移量

数字 访问子域时要删除的主机点分隔部分的数量。 2

信任代理

多种

指示应用程序位于面向前端的代理后面,并使用X-Forwarded-*标头来确定连接和客户端的 IP 地址。注意:X-Forwarded-*标头很容易被伪造,检测到的 IP 地址不可靠。

启用后,Express 会尝试确定通过面向前端的代理或一系列代理连接的客户端的 IP 地址。然后,req.ips 属性包含客户端连接经过的 IP 地址数组。要启用它,请使用信任代理选项表中描述的值。

trust proxy设置使用proxy-addr包实现。有关更多信息,请参阅其文档。

注意:子应用程序继承此设置的值,即使它具有默认值。

false(禁用)

视图

字符串或数组 应用程序视图的目录或目录数组。如果为数组,则按数组中出现的顺序查找视图。

process.cwd() + '/views'

视图缓存

布尔值

启用视图模板编译缓存。

注意:子应用程序在生产环境(当NODE_ENV为“production”时)不会继承此设置的值。

生产环境中为true,否则为未定义。

视图引擎

字符串 省略时使用的默认引擎扩展名。

注意:子应用程序将继承此设置的值。

N/A(未定义)

x-powered-by

布尔值 启用“X-Powered-By: Express”HTTP 标头。

true

trust proxy设置的选项

阅读Express 在代理后面以了解更多信息。

类型
布尔值

如果为true,则客户端的 IP 地址被理解为X-Forwarded-*标头中最左侧的条目。

如果为false,则应用程序被理解为直接面向互联网,并且客户端的 IP 地址来自req.connection.remoteAddress。这是默认设置。

字符串
包含逗号分隔值的字符串
字符串数组

一个 IP 地址、子网或一个 IP 地址和子网数组,用于信任。预配置的子网名称为

  • loopback - 127.0.0.1/8, ::1/128
  • linklocal - 169.254.0.0/16, fe80::/10
  • uniquelocal - 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7

通过以下任何方式设置 IP 地址

指定单个子网

app.set('trust proxy', 'loopback')

指定子网和地址

app.set('trust proxy', 'loopback, 123.123.123.123')

将多个子网指定为 CSV

app.set('trust proxy', 'loopback, linklocal, uniquelocal')

将多个子网指定为数组

app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal'])

指定后,IP 地址或子网将从地址确定过程中排除,并且最靠近应用程序服务器的不可信 IP 地址将被确定为客户端的 IP 地址。

数字

信任从面向前端的代理服务器开始的第 n 个跳跃作为客户端。

函数

自定义信任实现。仅当您知道自己在做什么时才使用它。

app.set('trust proxy', function (ip) {
  if (ip === '127.0.0.1' || ip === '123.123.123.123') return true // trusted IPs
  else return false
})
`etag` 设置选项

注意:这些设置仅适用于动态文件,不适用于静态文件。 express.static 中间件会忽略这些设置。

ETag 功能是使用 etag 包实现的。有关更多信息,请参阅其文档。

类型
布尔值

true 启用弱 ETag。这是默认设置。
false 完全禁用 ETag。

字符串 如果为“strong”,则启用强 ETag。
如果为“weak”,则启用弱 ETag。
函数

自定义 ETag 函数实现。仅当您知道自己在做什么时才使用它。

app.set('etag', function (body, encoding) {
  return generateHash(body, encoding) // consider the function is defined
})

app.use([path,] callback [, callback...])

在指定路径上安装指定的 中间件 函数或函数:当请求路径的基准与 path 匹配时,将执行中间件函数。

参数

参数 描述 默认值
路径 中间件函数被调用的路径;可以是以下任何一种:
  • 表示路径的字符串。
  • 路径模式。
  • 匹配路径的正则表达式模式。
  • 上述任何组合的数组。
有关示例,请参见 路径示例
'/'(根路径)
回调 回调函数;可以是
  • 中间件函数。
  • 一系列中间件函数(用逗号分隔)。
  • 中间件函数的数组。
  • 上述所有内容的组合。

您可以提供多个回调函数,这些函数的行为就像中间件一样,只是这些回调可以调用 next('route') 来绕过剩余的路由回调。您可以使用此机制对路由施加先决条件,然后在没有理由继续当前路由的情况下将控制权传递给后续路由。

由于 路由器应用程序 实现了中间件接口,因此您可以像使用任何其他中间件函数一样使用它们。

有关示例,请参见 中间件回调函数示例

描述

路由将匹配任何紧随其路径的路径,并以“/”结尾。例如:app.use('/apple', ...) 将匹配“/apple”、“/apple/images”、“/apple/images/news”等等。

由于 path 默认值为“/”,因此在没有路径的情况下安装的中间件将针对应用程序的每个请求执行。
例如,此中间件函数将针对应用程序的每个请求执行

app.use(function (req, res, next) {
  console.log('Time: %d', Date.now())
  next()
})

注意

子应用程序将

  • 不继承具有默认值的设置的值。您必须在子应用程序中设置该值。
  • 继承没有默认值的设置的值。

有关详细信息,请参阅 应用程序设置

中间件函数按顺序执行,因此中间件包含的顺序很重要。

// this middleware will not allow the request to go beyond it
app.use(function (req, res, next) {
  res.send('Hello World')
})

// requests will never reach this route
app.get('/', function (req, res) {
  res.send('Welcome')
})

错误处理中间件

错误处理中间件始终采用四个参数。您必须提供四个参数才能将其识别为错误处理中间件函数。即使您不需要使用 next 对象,也必须指定它以保持签名。否则,next 对象将被解释为常规中间件,并且将无法处理错误。有关错误处理中间件的详细信息,请参阅:错误处理

定义错误处理中间件函数的方式与其他中间件函数相同,只是参数从三个变为四个,具体签名为(err, req, res, next)

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

路径示例

下表提供了一些用于挂载中间件的有效path值的简单示例。

类型 示例
路径

这将匹配以/abcd开头的路径

app.use('/abcd', function (req, res, next) {
  next()
})
路径模式

这将匹配以/abcd/abd开头的路径

app.use('/abc?d', function (req, res, next) {
  next()
})

这将匹配以/abcd/abbcd/abbbbbcd等开头的路径

app.use('/ab+cd', function (req, res, next) {
  next()
})

这将匹配以/abcd/abxcd/abFOOcd/abbArcd等开头的路径

app.use('/ab*cd', function (req, res, next) {
  next()
})

这将匹配以/ad/abcd开头的路径

app.use('/a(bc)?d', function (req, res, next) {
  next()
})
正则表达式

这将匹配以/abc/xyz开头的路径

app.use(/\/abc|\/xyz/, function (req, res, next) {
  next()
})
数组

这将匹配以/abcd/xyza/lmn/pqr开头的路径

app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) {
  next()
})

中间件回调函数示例

下表提供了一些可以作为app.use()app.METHOD()app.all()callback参数使用的中间件函数的简单示例。即使示例是针对app.use(),它们也适用于app.use()app.METHOD()app.all()

用法 示例
单个中间件

您可以定义并本地挂载中间件函数。

app.use(function (req, res, next) {
  next()
})

路由器是有效的中间件。

var router = express.Router()
router.get('/', function (req, res, next) {
  next()
})
app.use(router)

Express 应用程序是有效的中间件。

var subApp = express()
subApp.get('/', function (req, res, next) {
  next()
})
app.use(subApp)
一系列中间件

您可以在同一个挂载路径上指定多个中间件函数。

var r1 = express.Router()
r1.get('/', function (req, res, next) {
  next()
})

var r2 = express.Router()
r2.get('/', function (req, res, next) {
  next()
})

app.use(r1, r2)
数组

使用数组以逻辑方式对中间件进行分组。

var r1 = express.Router()
r1.get('/', function (req, res, next) {
  next()
})

var r2 = express.Router()
r2.get('/', function (req, res, next) {
  next()
})

app.use([r1, r2])
组合

您可以将以上所有挂载中间件的方式组合起来。

function mw1 (req, res, next) { next() }
function mw2 (req, res, next) { next() }

var r1 = express.Router()
r1.get('/', function (req, res, next) { next() })

var r2 = express.Router()
r2.get('/', function (req, res, next) { next() })

var subApp = express()
subApp.get('/', function (req, res, next) { next() })

app.use(mw1, [mw2, r1, r2], subApp)

以下是一些在 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', function (req, res) {
  res.send('user ' + req.params.id)
})

但您也可以

app.get('/user/:id', function (request, response) {
  response.send('user ' + request.params.id)
})

req对象是 Node 自身请求对象的增强版本,支持所有内置字段和方法

属性

在 Express 4 中,req.files默认情况下不再在req对象上可用。要访问req.files对象上的上传文件,请使用多部分处理中间件,例如busboymulterformidablemultipartyconnect-multipartypez

req.app

此属性保存对使用中间件的 Express 应用程序实例的引用。

如果您遵循创建仅导出中间件函数的模块并在主文件中 require() 它的模式,则中间件可以通过 req.app 访问 Express 实例。

例如

// index.js
app.get('/viewdirectory', require('./mymiddleware.js'))
// mymiddleware.js
module.exports = function (req, res) {
  res.send('The views directory is ' + req.app.get('views'))
}

req.baseUrl

路由器实例被挂载的 URL 路径。

req.baseUrl 属性类似于 app 对象的 mountpath 属性,不同之处在于 app.mountpath 返回匹配的路径模式。

例如

var greet = express.Router()

greet.get('/jp', function (req, res) {
  console.log(req.baseUrl) // /greet
  res.send('Konichiwa!')
})

app.use('/greet', greet) // load the router on '/greet'

即使您使用路径模式或一组路径模式来加载路由器,baseUrl 属性也会返回匹配的字符串,而不是模式。在以下示例中,greet 路由器加载到两个路径模式上。

app.use(['/gre+t', '/hel{2}o'], greet) // load the router on '/gre+t' and '/hel{2}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

var express = require('express')

var 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', function (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.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-Forclient, proxy1, proxy2,则 req.ips 将为 ["client", "proxy1", "proxy2"],其中 proxy2 是最下游的代理。

req.method

包含与请求的 HTTP 方法相对应的字符串:GETPOSTPUT 等等。

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.baseUrlreq.url 的组合。请考虑以下示例

app.use('/admin', function (req, res, next) { // GET 'http://www.example.com/admin/new?sort=desc'
  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 个捕获组。此规则适用于使用字符串路由(如 /file/*)的未命名通配符匹配。

// 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

var qs = require('qs')
app.set('query parser', function (str) {
  return qs.parse(str, { /* custom options */ })
})

查看 查询解析器应用程序设置 文档以了解其他自定义选项。

req.res

此属性保存对与该请求对象相关的 响应对象 的引用。

req.route

包含当前匹配的路由,一个字符串。例如

app.get('/user/:id?', function userIdHandler (req, res) {
  console.log(req.route)
  res.send('GET')
})

前一段代码的示例输出

{ path: '/user/:id?',
  stack:
   [ { handle: [Function: userIdHandler],
       name: 'userIdHandler',
       params: undefined,
       path: undefined,
       keys: [],
       regexp: /^\/?$/i,
       method: 'get' } ],
  methods: { get: true } }

req.secure

一个布尔属性,如果建立了 TLS 连接,则为真。等同于

console.dir(req.protocol === 'https')
// => true

req.signedCookies

使用 cookie-parser 中间件时,此属性包含请求发送的已签名 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() 将返回 HTTP Accept-Language 头中的所有语言,作为 Array

有关更多信息,或者如果您有任何问题或疑虑,请参阅 accepts

Express (4.x) 源代码:request.js 第 179 行

Accepts (1.3) 源代码:index.js 第 195 行

req.get(field)

返回指定的 HTTP 请求头字段(不区分大小写匹配)。ReferrerReferer 字段是可互换的。

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.param(name [, defaultValue])

已弃用。根据需要使用 req.paramsreq.bodyreq.query

如果存在,则返回参数 name 的值。

// ?name=tobi
req.param('name')
// => "tobi"

// POST name=tobi
req.param('name')
// => "tobi"

// /user/tobi for /user/:name
req.param('name')
// => "tobi"

查找顺序如下

  • req.params
  • req.body
  • req.query

可选地,您可以指定 defaultValue,如果在任何请求对象中都找不到参数,则设置默认值。

为了清晰起见,应优先使用对 req.bodyreq.paramsreq.query 的直接访问 - 除非您确实接受来自每个对象的输入。

为了使 req.param() 可预测地工作,必须加载主体解析中间件。有关详细信息,请参阅 req.body

req.range(size[, options])

Range 标头解析器。

size 参数是资源的最大大小。

options 参数是一个对象,可以具有以下属性。

属性 类型 描述
combine 布尔值 指定是否应合并重叠和相邻范围,默认为 false。当 true 时,范围将被合并并返回,就好像它们是在标头中以这种方式指定的。

将返回一个范围数组或表示解析错误的负数。

  • -2 表示标头字符串格式错误
  • -1 表示无法满足的范围
// parse header from request
var range = req.range(1000)

// the type of the range
if (range.type === 'bytes') {
  // the ranges
  range.forEach(function (r) {
    // do something with r.start and r.end
  })
}

响应

res 对象表示 Express 应用程序在收到 HTTP 请求时发送的 HTTP 响应。

在本文档中,以及按照惯例,该对象始终被称为 res(HTTP 请求为 req),但它的实际名称由您正在工作的回调函数的参数决定。

例如

app.get('/user/:id', function (req, res) {
  res.send('user ' + req.params.id)
})

但您也可以

app.get('/user/:id', function (request, response) {
  response.send('user ' + request.params.id)
})

res 对象是 Node 自身响应对象的增强版本,支持所有 内置字段和方法

属性

res.app

此属性保存对使用中间件的 Express 应用程序实例的引用。

res.app 与请求对象中的 req.app 属性相同。

res.headersSent

布尔属性,指示应用程序是否为响应发送了 HTTP 标头。

app.get('/', function (req, res) {
  console.dir(res.headersSent) // false
  res.send('OK')
  console.dir(res.headersSent) // true
})

res.locals

使用此属性设置使用 res.render 渲染的模板中可访问的变量。在 res.locals 上设置的变量在一个请求-响应周期内可用,并且不会在请求之间共享。

locals 对象由视图引擎用于渲染响应。对象键可能特别敏感,不应包含用户控制的输入,因为它可能会影响视图引擎的操作或提供跨站点脚本攻击的途径。有关其他注意事项,请参阅所用视图引擎的文档。

为了保留本地变量以供在请求之间的模板渲染使用,请改用 app.locals

此属性对于向应用程序中渲染的模板公开请求级信息(例如请求路径名称、已认证用户、用户设置等)很有用。

app.use(function (req, res, next) {
  // Make `user` and `authenticated` available in templates
  res.locals.user = req.user
  res.locals.authenticated = !req.user.anonymous
  next()
})

方法

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 设置为 valuevalue 参数可以是字符串或转换为 JSON 的对象。

options 参数是一个对象,可以具有以下属性。

属性 类型 描述
domain 字符串 cookie 的域名。默认为应用程序的域名。
encode 函数 用于 cookie 值编码的同步函数。默认为 encodeURIComponent
expires 日期 cookie 的 GMT 过期日期。如果未指定或设置为 0,则创建会话 cookie。
httpOnly 布尔值 将 cookie 标记为仅可由 Web 服务器访问。
最大年龄 数字 用于相对于当前时间以毫秒为单位设置过期时间的便捷选项。
路径 字符串 cookie 的路径。默认为“/”。
partitioned 布尔值 指示 cookie 应该使用分区存储进行存储。有关更多详细信息,请参阅 具有独立分区状态的 Cookie (CHIPS)
priority 字符串 “Priority” Set-Cookie 属性的值。
secure 布尔值 将 cookie 标记为仅与 HTTPS 一起使用。
signed 布尔值 指示是否应该对 cookie 进行签名。
sameSite 布尔值或字符串 “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 选项是一个便利选项,用于以毫秒为单位设置相对于当前时间的“过期时间”。以下是与上面第二个示例等效的示例。

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.signedCookie 对象访问此值。

res.clearCookie(name [, options])

清除由 name 指定的 cookie。有关 options 对象的详细信息,请参阅 res.cookie()

只有当给定的 options 与传递给 res.cookie()options 相同(不包括 expiresmaxAge)时,Web 浏览器和其他兼容客户端才会清除 cookie。

res.cookie('name', 'tobi', { path: '/admin' })
res.clearCookie('name', { path: '/admin' })

res.download(path [, filename] [, options] [, fn])

path 处的文件作为“附件”传输。通常,浏览器会提示用户下载。默认情况下,Content-Disposition 标头的“filename=”参数是从 path 参数派生的,但可以使用 filename 参数覆盖。如果 path 是相对路径,则它将基于进程的当前工作目录或提供的 root 选项。

此 API 提供对正在运行的文件系统的访问。确保 (a) 如果 path 参数包含用户输入,则构造它的方式是安全的,或者 (b) 将 root 选项设置为目录的绝对路径以包含访问权限。

当提供 root 选项时,Express 将验证作为 path 提供的相对路径是否将在给定的 root 选项内解析。

下表提供了有关 options 参数的详细信息。

可选的 options 参数从 Express v4.16.0 开始受支持。

属性 描述 默认值 可用性
最大年龄 以毫秒为单位或以 ms 格式 设置 Cache-Control 标头的 max-age 属性 0 4.16+
root 相对文件名根目录。   4.18+
最后修改时间 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', function (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])

结束响应过程。此方法实际上来自 Node 核心,特别是 http.ServerResponse 的 response.end() 方法

用于快速结束响应,无需任何数据。如果您需要使用数据进行响应,请改用 res.send()res.json() 等方法。

res.end()
res.status(404).end()

res.format(object)

在请求对象上对 Accept HTTP 标头执行内容协商(如果存在)。它使用 req.accepts() 根据可接受类型的质量值顺序选择请求的处理程序。如果未指定标头,则调用第一个回调。如果未找到匹配项,则服务器将以 406“不可接受”响应,或调用 default 回调。

选择回调时,将设置 Content-Type 响应标头。但是,您可以在回调中使用 res.set()res.type() 等方法来更改它。

以下示例将在 Accept 标头字段设置为“application/json”或“*/json”时响应 { "message": "hey" }(但是,如果它是“*/*”,则响应将是“hey”)。

res.format({
  'text/plain': function () {
    res.send('hey')
  },

  'text/html': function () {
    res.send('<p>hey</p>')
  },

  'application/json': function () {
    res.send({ message: 'hey' })
  },

  default: function () {
    // log the request and respond with 406
    res.status(406).send('Not Acceptable')
  }
})

除了规范化的 MIME 类型之外,您还可以使用映射到这些类型的扩展名,以实现稍微不那么冗长的实现

res.format({
  text: function () {
    res.send('hey')
  },

  html: function () {
    res.send('<p>hey</p>')
  },

  json: function () {
    res.send({ message: 'hey' })
  }
})

res.get(field)

返回由 field 指定的 HTTP 响应标头。匹配不区分大小写。

res.get('Content-Type')
// => "text/plain"

res.json([body])

发送 JSON 响应。此方法发送一个响应(带有正确的 content-type),该响应是使用 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 回调名称 设置覆盖它。

以下是一些使用相同代码的 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" })

将作为参数属性提供的 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')
res.location('back')

path 值为“back”具有特殊含义,它指的是请求的 Referer 标头中指定的 URL。如果未指定 Referer 标头,则它指的是“/”。

在对 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('..')

back 重定向将请求重定向回 referer,在 referer 丢失时默认为 /

res.redirect('back')

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', function (err, html) {
  res.send(html)
})

// pass a local variable to the view
res.render('user', { name: 'Tobi' }, function (err, html) {
  // ...
})

res.req

此属性保存对与该响应对象相关的 请求对象 的引用。

res.send([body])

发送 HTTP 响应。

body 参数可以是 Buffer 对象、String、对象、BooleanArray。例如

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>')

当参数是 ArrayObject 时,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 参数的详细信息。

属性 描述 默认值 可用性
最大年龄 以毫秒为单位或以 ms 格式 设置 Cache-Control 标头的 max-age 属性 0  
root 相对文件名根目录。    
最后修改时间 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', function (req, res, next) {
  var options = {
    root: path.join(__dirname, 'public'),
    dotfiles: 'deny',
    headers: {
      'x-timestamp': Date.now(),
      'x-sent': true
    }
  }

  var fileName = req.params.name
  res.sendFile(fileName, options, function (err) {
    if (err) {
      next(err)
    } else {
      console.log('Sent:', fileName)
    }
  })
})

以下示例说明了如何使用 res.sendFile 来提供对文件服务的细粒度支持

app.get('/user/:uid/photos/:file', function (req, res) {
  var uid = req.params.uid
  var file = req.params.file

  req.user.mayViewFilesFrom(uid, function (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 状态码(超出 100599 的范围)时会抛出异常。请查阅所用 Node.js 版本的 HTTP 服务器文档。

更多关于 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 包含“/”字符,则将其设置为 type 的确切值,否则将其视为文件扩展名,并使用 express.static.mime.lookup() 方法在映射中查找 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.vary(field)

将字段添加到 Vary 响应头中,如果它不存在。

res.vary('User-Agent').render('docs')

路由器

router 对象是中间件和路由的独立实例。您可以将其视为一个“迷你应用程序”,它只能执行中间件和路由功能。每个 Express 应用程序都具有一个内置的应用程序路由器。

路由器本身的行为类似于中间件,因此您可以将其用作 app.use() 的参数,或用作另一个路由器的 use() 方法的参数。

顶级 express 对象具有一个 Router() 方法,该方法创建一个新的 router 对象。

创建路由器对象后,您可以向其添加中间件和 HTTP 方法路由(例如 getputpost 等),就像应用程序一样。例如

// invoked for any requests passed to this router
router.use(function (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', function (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('*', requireAuthentication, loadUser)

或等效的

router.all('*', requireAuthentication)
router.all('*', loadUser)

另一个示例是白名单“全局”功能。这里示例与之前类似,但它只限制以“/api”为前缀的路径。

router.all('/api/*', requireAuthentication)

router.METHOD(path, [callback, ...] callback)

router.METHOD() 方法提供 Express 中的路由功能,其中 METHOD 是 HTTP 方法之一,例如 GET、PUT、POST 等,以小写形式表示。因此,实际方法是 router.get()router.post()router.put() 等。

如果在 router.get() 之前没有为路径调用 router.head(),则 router.get() 函数会自动为 HTTP HEAD 方法调用,除了 GET 方法。

您可以提供多个回调,所有回调都将被平等对待,并且行为与中间件类似,只是这些回调可能会调用 next('route') 以绕过剩余的路由回调。您可以使用此机制对路由执行先决条件,然后在没有理由继续执行匹配的路由时将控制权传递给后续路由。

以下代码片段说明了最简单的路由定义。Express 将路径字符串转换为正则表达式,在内部用于匹配传入的请求。在执行这些匹配时,不会考虑查询字符串,例如“GET /”将匹配以下路由,就像“GET /?name=tobi”一样。

router.get('/', function (req, res) {
  res.send('hello world')
})

您也可以使用正则表达式——如果您有非常具体的约束,这很有用,例如以下将匹配“GET /commits/71dbb9c”以及“GET /commits/71dbb9c..4c084f9”。

router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function (req, res) {
  var from = req.params[0]
  var to = req.params[1] || 'HEAD'
  res.send('commit range ' + from + '..' + to)
})

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', function (req, res, next, id) {
  // try to get the user details from the User model and attach it to the request object
  User.find(id, function (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', function (req, res, next, id) {
  console.log('CALLED ONLY ONCE')
  next()
})

router.get('/user/:id', function (req, res, next) {
  console.log('although this matches')
  next()
})

router.get('/user/:id', function (req, res) {
  console.log('and this matches too')
  res.end()
})

GET /user/42上,将打印以下内容

CALLED ONLY ONCE
although this matches
and this matches too

以下部分描述了 router.param(callback),该方法已在 v4.11.0 版本中弃用。

通过仅将函数传递给 router.param(),可以完全改变 router.param(name, callback) 方法的行为。此函数是 router.param(name, callback) 行为的自定义实现 - 它接受两个参数,并且必须返回一个中间件。

此函数的第一个参数是应该捕获的 URL 参数的名称,第二个参数可以是任何 JavaScript 对象,它可能用于返回中间件实现。

函数返回的中间件决定了捕获 URL 参数时发生的事情的行为。

在此示例中,router.param(name, callback) 签名被修改为 router.param(name, accessId)router.param() 现在将接受一个名称和一个数字,而不是接受一个名称和一个回调函数。

var express = require('express')
var app = express()
var router = express.Router()

// customizing the behavior of router.param()
router.param(function (param, option) {
  return function (req, res, next, val) {
    if (val === option) {
      next()
    } else {
      res.sendStatus(403)
    }
  }
})

// using the customized router.param()
router.param('id', '1337')

// route to trigger the capture
router.get('/user/:id', function (req, res) {
  res.send('OK')
})

app.use(router)

app.listen(3000, function () {
  console.log('Ready')
})

在此示例中,router.param(name, callback) 签名保持不变,但不是中间件回调函数,而是定义了一个自定义数据类型检查函数来验证用户 ID 的数据类型。

router.param(function (param, validator) {
  return function (req, res, next, val) {
    if (validator(val)) {
      next()
    } else {
      res.sendStatus(403)
    }
  }
})

router.param('id', function (candidate) {
  return !isNaN(parseFloat(candidate)) && isFinite(candidate)
})

router.route(path)

返回单个路由的实例,然后可以使用该实例来处理具有可选中间件的 HTTP 动词。使用 router.route() 来避免重复的路由命名,从而避免打字错误。

基于上面的 router.param() 示例,以下代码展示了如何使用 router.route() 来指定各种 HTTP 方法处理程序。

var router = express.Router()

router.param('user_id', function (req, res, next, id) {
  // sample user, would actually fetch from DB, etc...
  req.user = {
    id: id,
    name: 'TJ'
  }
  next()
})

router.route('/users/:user_id')
  .all(function (req, res, next) {
    // runs for all HTTP verbs first
    // think of it as route specific middleware!
    next()
  })
  .get(function (req, res, next) {
    res.json(req.user)
  })
  .put(function (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(function (req, res, next) {
    next(new Error('not implemented'))
  })
  .delete(function (req, res, next) {
    next(new Error('not implemented'))
  })

这种方法重新使用单个 /users/:user_id 路径,并为各种 HTTP 方法添加处理程序。

注意:当使用 router.route() 时,中间件排序基于创建路由的时间,而不是添加方法处理程序的时间。为此,您可以将方法处理程序视为属于它们被添加到的路由。

router.use([path], [function, ...] function)

使用指定的中间件函数或函数,带有可选的挂载路径 path,默认值为“/”。

此方法类似于 app.use()。下面描述了一个简单的示例和用例。有关更多信息,请参阅 app.use()

中间件就像一个管道:请求从定义的第一个中间件函数开始,并沿着中间件堆栈“向下”工作,为它们匹配的每个路径进行处理。

var express = require('express')
var app = express()
var router = express.Router()

// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function (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', function (req, res, next) {
  // ... maybe some additional /bar logging ...
  next()
})

// always invoked
router.use(function (req, res, next) {
  res.send('Hello World')
})

app.use('/foo', router)

app.listen(3000)

“挂载”路径被剥离,并且对中间件函数不可见。此功能的主要效果是,挂载的中间件函数可以在没有代码更改的情况下运行,无论其“前缀”路径名是什么。

使用 `router.use()` 定义中间件的顺序非常重要。它们按顺序调用,因此顺序决定了中间件的优先级。例如,通常记录器是您使用的第一个中间件,这样每个请求都会被记录。

var logger = require('morgan')
var path = require('path')

router.use(logger())
router.use(express.static(path.join(__dirname, 'public')))
router.use(function (req, res) {
  res.send('Hello')
})

现在假设您想忽略对静态文件的记录请求,但继续记录 `logger()` 之后定义的路由和中间件。您只需将对 `express.static()` 的调用移到最前面,在添加记录器中间件之前。

router.use(express.static(path.join(__dirname, 'public')))
router.use(logger())
router.use(function (req, res) {
  res.send('Hello')
})

另一个例子是从多个目录提供文件,优先级为“./public”高于其他目录。

router.use(express.static(path.join(__dirname, 'public')))
router.use(express.static(path.join(__dirname, 'files')))
router.use(express.static(path.join(__dirname, 'uploads')))

router.use() 方法也支持命名参数,以便您的其他路由的挂载点可以从使用命名参数的预加载中受益。

注意:虽然这些中间件函数是通过特定路由添加的,但它们运行的时间由它们附加到的路径(而不是路由)决定。因此,通过一个路由添加的中间件可能会在其他路由上运行,如果它的路由匹配。例如,这段代码展示了两个在相同路径上挂载的不同路由。

var authRouter = express.Router()
var openRouter = express.Router()

authRouter.use(require('./authenticate').basic(usersdb))

authRouter.get('/:user_id/edit', function (req, res, next) {
  // ... Edit user UI ...
})
openRouter.get('/', function (req, res, next) {
  // ... List users ...
})
openRouter.get('/:user_id', function (req, res, next) {
  // ... View user ...
})

app.use('/users', authRouter)
app.use('/users', openRouter)

即使身份验证中间件是通过 `authRouter` 添加的,它也会在 `openRouter` 定义的路由上运行,因为这两个路由都挂载在 `users` 上。为了避免这种行为,请为每个路由使用不同的路径。