黑人生命也是命。
支持平等正义倡议.

Express 3.x 不再维护

自上次更新(2015 年 8 月 1 日)以来,3.x 中已知的和未知的安全和性能问题尚未得到解决。强烈建议使用最新版本的 Express。

3.x API

express()

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

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

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

app.listen(3000)

应用程序

app.set(name, value)

将设置 name 分配给 value

app.set('title', 'My Site')
app.get('title')
// => "My Site"

app.get(name)

获取设置 name 值。

app.get('title')
// => undefined

app.set('title', 'My Site')
app.get('title')
// => "My Site"

app.enable(name)

将设置 name 设置为 true

app.enable('trust proxy')
app.get('trust proxy')
// => true

app.disable(name)

将设置 name 设置为 false

app.disable('trust proxy')
app.get('trust proxy')
// => false

app.enabled(name)

检查设置 name 是否已启用。

app.enabled('trust proxy')
// => false

app.enable('trust proxy')
app.enabled('trust proxy')
// => true

app.disabled(name)

检查设置 name 是否已禁用。

app.disabled('trust proxy')
// => true

app.enable('trust proxy')
app.disabled('trust proxy')
// => false

app.configure([env], callback)

envapp.get('env')(又名 process.env.NODE_ENV)匹配时,有条件地调用 callback。此方法保留用于传统原因,并且实际上是一个 if 语句,如下面的代码段所示。使用 app.set() 和其他配置方法时不需要这些函数。

// all environments
app.configure(function () {
  app.set('title', 'My Application')
})

// development only
app.configure('development', function () {
  app.set('db uri', 'localhost/dev')
})

// production only
app.configure('production', function () {
  app.set('db uri', 'n.n.n.n/prod')
})

实际上是以下内容的语法糖

// all environments
app.set('title', 'My Application')

// development only
if (app.get('env') === 'development') {
  app.set('db uri', 'localhost/dev')
}

// production only
if (app.get('env') === 'production') {
  app.set('db uri', 'n.n.n.n/prod')
}

app.use([path], function)

使用给定的中间件 function,可选挂载 path,默认为 “/”。

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

// simple logger
app.use(function (req, res, next) {
  console.log('%s %s', req.method, req.url)
  next()
})

// respond
app.use(function (req, res, next) {
  res.send('Hello World')
})

app.listen(3000)

“挂载”路径被剥离,并且对中间件 function不可见。此功能的主要作用是,无论其“前缀”路径名如何,已挂载的中间件都可以操作,而无需更改代码。

路由将匹配紧跟其路径的任何路径,后面紧跟 “/” 或 “.”。例如:app.use('/apple', ...) 将匹配 /apple/apple/images/apple/images/news/apple.html/apple.html.txt 等。

这里有一个具体示例,使用 express.static() 中间件在 ./public 中提供文件

// GET /javascripts/jquery.js
// GET /style.css
// GET /favicon.ico
app.use(express.static(path.join(__dirname, 'public')))

例如,如果你想使用“/static”作为所有静态文件的前缀,可以使用“挂载”功能来支持此操作。挂载的中间件函数不会被调用,除非req.url包含此前缀,此时在调用函数时会将该前缀去除。这仅影响此函数,后续中间件将看到包含“/static”的req.url,除非它们也已挂载。

// GET /static/javascripts/jquery.js
// GET /static/style.css
// GET /static/favicon.ico
app.use('/static', express.static(path.join(__dirname, 'public')))

使用app.use()“定义”中间件的顺序非常重要,它们按顺序调用,因此这定义了中间件优先级。例如,通常express.logger()是你会使用的第一个中间件,它会记录每个请求

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

现在,假设你想忽略对静态文件的记录请求,但继续记录logger()之后定义的路由和中间件,你只需将static()移到上面

app.use(express.static(path.join(__dirname, 'public')))
app.use(express.logger())
app.use(function (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')))

设置

提供了以下设置来改变 Express 的行为

  • env 环境模式,默认为 process.env.NODE_ENV 或“development”
  • trust proxy 启用反向代理支持,默认情况下禁用
  • jsonp callback name 更改默认回调名称 ?callback=
  • json replacer JSON 替换回调,默认为 null
  • json spaces 用于格式化的 JSON 响应空格,在开发环境中默认为 2,在生产环境中默认为 0
  • case sensitive routing 启用大小写敏感性,默认情况下禁用,将“/Foo”和“/foo”视为相同
  • strict routing 启用严格路由,默认情况下,路由器将“/foo”和“/foo/”视为相同
  • view cache 启用视图模板编译缓存,在生产环境中默认启用
  • view engine 省略时要使用的默认引擎扩展名
  • views 视图目录路径,默认为“process.cwd() + ‘/views’”

app.engine(ext, callback)

将给定的模板引擎callback注册为ext

默认情况下,会根据文件扩展名require()引擎。例如,如果你尝试渲染“foo.jade”文件,Express 将在内部调用以下内容,并在后续调用中缓存require()以提高性能。

app.engine('jade', require('jade').__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.param([name], callback)

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

以下代码段说明了 callback 在很大程度上类似于中间件,因此支持异步操作,但提供了参数的附加值,此处命名为 id。然后尝试加载用户,分配 req.user,否则将错误传递给 next(err)

app.param('user', function (req, res, next, id) {
  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'))
    }
  })
})

或者,你只能传递一个 callback,在这种情况下,你有机会更改 app.param() API。例如,express-params 定义了以下回调,允许你将参数限制为给定的正则表达式。

此示例稍微高级一些,它检查第二个参数是否为正则表达式,并返回一个回调,其行为与 “user” 参数示例非常相似。

app.param(function (name, fn) {
  if (fn instanceof RegExp) {
    return function (req, res, next, val) {
      var captures
      if ((captures = fn.exec(String(val)))) {
        req.params[name] = captures
        next()
      } else {
        next('route')
      }
    }
  }
})

现在可以使用该方法有效地验证参数,或者解析它们以提供捕获组。

app.param('id', /^\d+$/)

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

app.param('range', /^(\w+)\.\.(\w+)?$/)

app.get('/range/:range', function (req, res) {
  var range = req.params.range
  res.send('from ' + range[1] + ' to ' + range[2])
})

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

app.VERB() 方法在 Express 中提供路由功能,其中 VERB 是 HTTP 动词之一,例如 app.post()。可以给出多个回调,所有回调都同等对待,并且表现得完全像中间件,但有一个例外,即这些回调可以调用 next('route') 以绕过剩余的路由回调。此机制可用于对路由执行前置条件,然后在没有理由继续匹配的路由时将控制权传递给后续路由。

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

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

还可使用正则表达式,如果你有非常具体的限制,这会很有用,例如以下内容将匹配“GET /commits/71dbb9c”以及“GET /commits/71dbb9c..4c084f9”。

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

还可以传递多个回调,这对于重新使用加载资源、执行验证等的中间件非常有用。

app.get('/user/:id', user.load, function () {
  // ...
})

这些回调也可以在数组中传递,这些数组在传递时会被简单地展平

var middleware = [loadForum, loadThread]

app.get('/forum/:fid/thread/:tid', middleware, function () {
  // ...
})

app.post('/forum/:fid/thread/:tid', middleware, function () {
  // ...
})

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

此方法的功能与 app.VERB() 方法类似,但它匹配所有 HTTP 动词。

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

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

或等效项

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

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

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

app.locals

应用程序本地变量提供给应用程序中呈现的所有模板。这对于向模板提供帮助器函数以及应用程序级数据非常有用。

app.locals.title = 'My App'
app.locals.strftime = require('strftime')

app.locals 对象是一个 JavaScript Function,当使用对象调用它时,它会将属性合并到自身中,提供一种简单的方法来将现有对象公开为本地变量。

app.locals({
  title: 'My App',
  phone: '1-250-858-9990',
  email: '[email protected]'
})

console.log(app.locals.title)
// => 'My App'

console.log(app.locals.email)
// => '[email protected]'

app.locals 对象最终是一个 JavaScript 函数对象,因此你不能为自己的变量名重复使用现有的(本机)命名属性,例如 name, apply, bind, call, arguments, length, constructor

app.locals({ name: 'My App' })

console.log(app.locals.name)
// => return 'app.locals' in place of 'My App' (app.locals is a Function !)
// => if name's variable is used in a template, a ReferenceError will be returned.

可以在许多规范中找到本机命名属性的完整列表。 JavaScript 规范 引入了原始属性,其中一些属性仍被现代引擎识别,然后 EcmaScript 规范 在此基础上构建并规范化了属性集,添加了新属性并删除了已弃用的属性。如有兴趣,请查看函数和对象的属性。

默认情况下,Express 仅公开一个应用程序级本地变量 settings

app.set('title', 'My App')
// use settings.title in a view

app.render(view, [options], callback)

使用回调呈现一个 view,并使用呈现的字符串进行响应。这是 res.render() 的应用程序级别变体,并且其他行为方式相同。

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

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

app.routes

app.routes 对象包含所有已定义的路由,这些路由由关联的 HTTP 动词映射。此对象可用于自省功能,例如 Express 在内部不仅将其用于路由,还用于提供默认

OPTIONS

行为,除非使用 app.options()。您的应用程序或框架还可以通过简单地从该对象中删除路由来删除路由。

console.log(app.routes) 的输出

{ get:
   [ { path: '/',
       method: 'get',
       callbacks: [Object],
       keys: [],
       regexp: /^\/\/?$/i },
     { path: '/user/:id',
       method: 'get',
       callbacks: [Object],
       keys: [{ name: 'id', optional: false }],
       regexp: /^\/user\/(?:([^\/]+?))\/?$/i } ],
  delete:
   [ { path: '/user/:id',
       method: 'delete',
       callbacks: [Object],
       keys: [Object],
       regexp: /^\/user\/(?:([^\/]+?))\/?$/i } ] }

app.listen()

在给定的主机和端口上绑定并侦听连接,此方法与节点的 http.Server#listen() 相同。

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

express() 返回的 app 实际上是一个 JavaScript Function,旨在作为回调传递给节点的 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() 方法只是一个便利方法,定义为,如果您希望使用 HTTPS 或同时提供,请使用上述技术。

app.listen = function () {
  var server = http.createServer(this)
  return server.listen.apply(server, arguments)
}

请求

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

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

此属性是一个包含已解析查询字符串的对象,默认为 {}

// GET /search?q=tobi+ferret
console.dir(req.query.q)
// => 'tobi ferret'

// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
console.dir(req.query.order)
// => 'desc'

console.dir(req.query.shoe.color)
// => 'blue'

console.dir(req.query.shoe.type)
// => 'converse'

req.body

此属性是一个包含已解析请求正文的对象。此功能由 bodyParser() 中间件提供,但其他正文解析中间件也可能遵循此约定。当使用 bodyParser() 时,此属性默认为 {}

// POST user[name]=tobi&user[email][email protected]
console.log(req.body.user.name)
// => "tobi"

console.log(req.body.user.email)
// => "[email protected]"

// POST { "name": "tobi" }
console.log(req.body.name)
// => "tobi"

req.files

此属性是已上传文件的对象。此功能由 bodyParser() 中间件提供,但其他正文解析中间件也可能遵循此约定。当使用 bodyParser() 时,此属性默认为 {}

例如,如果一个 file 字段被命名为“image”,并且上传了一个文件,则 req.files.image 将包含以下 File 对象

{ size: 74643,
  path: '/tmp/8ef9c52abe857867fd0a4e9a819d1876',
  name: 'edge.png',
  type: 'image/png',
  hash: false,
  lastModifiedDate: Thu Aug 09 2012 20:07:51 GMT-0700 (PDT),
  _writeStream:
   { path: '/tmp/8ef9c52abe857867fd0a4e9a819d1876',
     fd: 13,
     writable: false,
     flags: 'w',
     encoding: 'binary',
     mode: 438,
     bytesWritten: 74643,
     busy: false,
     _queue: [],
     _open: [Function],
     drainable: true },
  length: [Getter],
  filename: [Getter],
  mime: [Getter] }

bodyParser() 中间件在内部使用 node-formidable 模块,并接受相同选项。一个示例是 formidable 选项 keepExtensions,其默认值为 false,在这种情况下,它会提供不带 “.png” 扩展名的文件名 “/tmp/8ef9c52abe857867fd0a4e9a819d1876”。若要启用此选项或其他选项,可以将它们传递给 bodyParser()

app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/my/files' }))

req.param(name)

在存在时返回参数 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

除非您真正接受来自每个对象的输入,否则应优先直接访问 req.bodyreq.paramsreq.query 以提高清晰度。

req.route

当前匹配的 Route,包含多个属性,例如路由的原始路径字符串、生成的正则表达式等。

app.get('/user/:id?', function (req, res) {
  console.dir(req.route)
})

前一个代码段的示例输出

{ path: '/user/:id?',
  method: 'get',
  callbacks: [ [Function] ],
  keys: [ { name: 'id', optional: true } ],
  regexp: /^\/user(?:\/([^\/]+?))?\/?$/i,
  params: [ id: '12' ] }

req.cookies

此对象需要 cookieParser() 中间件才能使用。它包含用户代理发送的 cookie。如果没有发送 cookie,则默认为 {}

// Cookie: name=tj
console.log(req.cookies.name)
// => "tj"

req.signedCookies

此对象需要 cookieParser(secret) 中间件才能使用。它包含用户代理发送的已签名 cookie,这些 cookie 未签名且可以使用。已签名 cookie 驻留在不同的对象中以显示开发人员意图;否则,恶意攻击可能会放置在 req.cookie 值(很容易欺骗)上。请注意,对 cookie 进行签名并不会使其“隐藏”或加密;这只是防止篡改(因为用于签名的密钥是私有的)。如果没有发送已签名 cookie,则默认为 {}

// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
console.dir(req.signedCookies.user)
// => 'tobi'

req.get(field)

获取不区分大小写的请求头 field。“Referrer” 和 “Referer” 字段可以互换。

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

req.get('content-type')
// => "text/plain"

req.get('Something')
// => undefined

p 别名为 req.header(field)

req.accepts(types)

检查给定的 types 是否可接受,在为 true 时返回最佳匹配,否则返回 undefined - 在这种情况下,您应该使用 406 “不可接受” 进行响应。

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')
// => undefined

// Accept: text/*;q=.5, application/json
req.accepts(['html', 'json'])
req.accepts('html, json')
// => "json"

req.accepted

返回一个已接受媒体类型的数组,按从最高质量到最低质量排序。

[ { value: 'application/json',
    quality: 1,
    type: 'application',
    subtype: 'json' },
   { value: 'text/html',
     quality: 0.5,
     type: 'text',
     subtype: 'html' } ]

req.is(type)

检查传入请求是否包含 “Content-Type” 头字段,以及它是否与给定的 MIME type 匹配。

// With Content-Type: text/html; charset=utf-8
req.is('html')
req.is('text/html')
req.is('text/*')
// => true

// When Content-Type is application/json
req.is('json')
req.is('application/json')
req.is('application/*')
// => true

req.is('html')
// => false

req.ip

返回远程地址,或者在启用 “信任代理” 时返回上游地址。

console.dir(req.ip)
// => '127.0.0.1'

req.ips

当“trust proxy”为true时,解析“X-Forwarded-For”IP 地址列表并返回一个数组,否则返回一个空数组。

例如,如果值为“client, proxy1, proxy2”,您将收到数组["client", "proxy1", "proxy2"],其中“proxy2”是最远的下游。

req.path

返回请求 URL 路径名。

// example.com/users?sort=desc
console.dir(req.path)
// => '/users'

req.host

从“Host”头字段(不含端口号)返回主机名。

// Host: "example.com:3000"
console.dir(req.host)
// => 'example.com'

req.fresh

检查请求是否新鲜 - 又称 Last-Modified 和/或 ETag 仍然匹配,表明资源是“新鲜的”。

console.dir(req.fresh)
// => true

req.stale

检查请求是否陈旧 - 又称 Last-Modified 和/或 ETag 不匹配,表明资源是“陈旧的”。

console.dir(req.stale)
// => true

req.xhr

检查请求是否已发出“X-Requested-With”头字段设置为“XMLHttpRequest”(jQuery 等)。

console.dir(req.xhr)
// => true

req.protocol

当使用 TLS 请求时,返回协议字符串“http”或“https”。当启用“trust proxy”设置时,将信任“X-Forwarded-Proto”头字段。如果您在为您提供 https 的反向代理后面运行,则可以启用此功能。

console.dir(req.protocol)
// => 'http'

req.secure

检查是否建立了 TLS 连接。这是

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

req.subdomains

将子域作为数组返回。

// Host: "tobi.ferrets.example.com"
console.dir(req.subdomains)
// => ['ferrets', 'tobi']

req.originalUrl

此属性非常类似于req.url,但它保留了原始请求 URL,允许您自由地重写req.url以用于内部路由目的。例如,app.use()的“挂载”功能将重写req.url以删除挂载点。

// GET /search?q=something
console.log(req.originalUrl)
// => "/search?q=something"

req.acceptedLanguages

从最高质量到最低质量返回一个已接受语言的数组。

Accept-Language: en;q=.5, en-us
// => ['en-us', 'en']

req.acceptedCharsets

从最高质量到最低质量返回一个已接受字符集的数组。

Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
// => ['unicode-1-1', 'iso-8859-5']

req.acceptsCharset(charset)

检查给定的charset是否可以接受。

req.acceptsLanguage(lang)

检查给定的lang是否可以接受。

req.res

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

响应

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

res.status(code)

Node 的res.statusCode=的可链接别名。

res.status(404).sendfile('path/to/404.png')

res.set(field, [value])

将头field设置为value,或传递一个对象以一次设置多个字段。

res.set('Content-Type', 'text/plain')

res.set({
  'Content-Type': 'text/plain',
  'Content-Length': '123',
  ETag: '12345'
})

别名为res.header(field, [value])

res.get(field)

获取不区分大小写的响应头field

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

res.cookie(name, value, [options])

将 cookie name 设置为 value,它可以是字符串或转换为 JSON 的对象。path 选项默认为“/”。

res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true })
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })

maxAge 选项是一个便捷选项,用于根据当前时间以毫秒为单位设置“expires”。以下等效于之前的示例。

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })

可以传递一个对象,然后将其序列化为 JSON,bodyParser() 中间件会自动解析它。

res.cookie('cart', { items: [1, 2, 3] })
res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 })

此方法还支持签名 cookie。只需传递 signed 选项。当给定 res.cookie() 时,它将使用传递给 express.cookieParser(secret) 的密钥对值进行签名。

res.cookie('name', 'tobi', { signed: true })

稍后,您可以通过 req.signedCookie 对象访问此值。

res.clearCookie(name, [options])

清除 cookie namepath 选项默认为“/”。

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

res.redirect([status], url)

使用可选的 status 代码(默认为 302 “Found”)重定向到给定的 url

res.redirect('/foo/bar')
res.redirect('http://example.com')
res.redirect(301, 'http://example.com')
res.redirect('../login')

Express 支持几种重定向形式,首先是完全限定的 URI,用于重定向到其他站点

res.redirect('http://google.com')

第二种形式是路径名相对重定向,例如,如果您在 http://example.com/admin/post/new 上,则以下重定向到 /admin 会将您带到 http://example.com/admin

res.redirect('/admin')

此下一个重定向相对于应用程序的 mount 点。例如,如果您有一个安装在 /blog 上的博客应用程序,理想情况下它不知道它安装在哪里,因此重定向 /admin/post/new 只会给您 http://example.com/admin/post/new,以下安装相对重定向将给您 http://example.com/blog/admin/post/new

res.redirect('admin/post/new')

路径名相对重定向也是可能的。如果您在 http://example.com/admin/post/new 上,则以下重定向将使您到达 http//example.com/admin/post

res.redirect('..')

最后一种特殊情况是 back 重定向,重定向回引用者(或推荐者),缺失时默认为 /

res.redirect('back')

res.location

设置位置标头。

res.location('/foo/bar')
res.location('foo/bar')
res.location('http://example.com')
res.location('../login')
res.location('back')

您可以使用与 res.redirect() 中相同的 url

例如,如果您的应用程序安装在 /blog 上,则以下内容将 location 标头设置为 /blog/admin

res.location('admin')

res.charset

分配字符集。默认为“utf-8”。

res.charset = 'value'
res.send('<p>some html</p>')
// => Content-Type: text/html; charset=value

res.send([body|status], [body])

发送响应。

res.send(Buffer.from('whoop'))
res.send({ some: 'json' })
res.send('<p>some html</p>')
res.send(404, 'Sorry, we cannot find that!')
res.send(500, { error: 'something blew up' })
res.send(200)

此方法对简单的非流式响应执行许多有用的任务,例如自动分配 Content-Length(除非之前已定义)并提供自动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])

最后,当给定Number且没有前面提到的任何正文时,将为您分配一个响应正文字符串。例如,200 将响应文本“OK”,404 为“Not Found”,依此类推。

res.send(200)
res.send(404)
res.send(500)

res.json([status|body], [body])

发送 JSON 响应。当传递对象或数组时,此方法与res.send()相同,但可用于非对象的显式 JSON 转换(null、undefined 等),尽管从技术上讲这些不是有效的 JSON。

res.json(null)
res.json({ user: 'tobi' })
res.json(500, { error: 'message' })

res.jsonp([status|body], [body])

发送带有 JSONP 支持的 JSON 响应。此方法与res.json()相同,但选择加入 JSONP 回调支持。

res.jsonp(null)
// => null

res.jsonp({ user: 'tobi' })
// => { "user": "tobi" }

res.jsonp(500, { error: 'message' })
// => { "error": "message" }

默认情况下,JSONP 回调名称只是callback,但您可以使用jsonp 回调名称设置对此进行更改。以下是使用相同代码的一些 JSONP 响应示例

// ?callback=foo
res.jsonp({ user: 'tobi' })
// => foo({ "user": "tobi" })

app.set('jsonp callback name', 'cb')

// ?cb=foo
res.jsonp(500, { error: 'message' })
// => foo({ "error": "message" })

res.type(type)

将 Content-Type 设置为type的 mime 查找,或者当存在“/”时,Content-Type 只是简单地设置为此文字值。

res.type('.html')
res.type('html')
res.type('json')
res.type('application/json')
res.type('png')

p 别名为res.contentType(type)

res.format(object)

当存在时,对请求 Accept 头字段执行内容协商。此方法使用req.accepted,这是一个按其质量值排序的可接受类型数组,否则将调用第一个回调。当没有执行匹配时,服务器将响应 406“Not Acceptable”,或调用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' })
  }
})

除了规范化的 MIME 类型外,您还可以使用映射到这些类型的扩展名,从而提供一个不太冗长的实现

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

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

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

res.attachment([filename])

将 Content-Disposition 头字段设置为“attachment”。如果给出了 filename,则 Content-Type 将根据 extname 通过 res.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.sendfile(path, [options], [fn]])

传输给定 path 处的文件。

根据文件名扩展名自动默认为 Content-Type 响应头字段。当传输完成或发生错误时,将调用回调 fn(err)

选项

  • maxAge,以毫秒为单位,默认为 0
  • root,相对文件名的根目录

此方法提供对文件服务的细粒度支持,如下例所示

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.send(403, 'Sorry! you cant see that.')
    }
  })
})

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

path 处的文件作为“附件”传输,通常浏览器会提示用户下载。Content-Disposition “filename=”参数(即浏览器对话框中显示的参数)默认设置为 path,但你可以提供一个覆盖 filename

当发生错误或传输完成时,将调用可选回调 fn。此方法使用 res.sendfile() 传输文件。

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, keep in mind the response may be partially-sent
    // so check res.headerSent
  } else {
    // decrement a download credit etc
  }
})

连接给定的 links 以填充“Link”响应头字段。

res.links({
  next: 'http://api.example.com/users?page=2',
  last: 'http://api.example.com/users?page=5'
})

p 生成

Link: <http://api.example.com/users?page=2> rel="next",
      <http://api.example.com/users?page=5> rel="last"

res.locals

响应本地变量的作用域限定在请求中,因此仅在该请求/响应周期(如果有)期间呈现的视图中可用。否则,此 API 与 app.locals 相同。

此对象对于公开请求级信息(例如请求路径名、经过身份验证的用户、用户设置等)非常有用。

app.use(function (req, res, next) {
  res.locals.user = req.user
  res.locals.authenticated = !req.user.anonymous
  next()
})

res.render(view, [locals], callback)

使用回调呈现 view,并使用呈现的字符串进行响应。当发生错误时,将在内部调用 next(err)。当提供回调时,将传递可能的错误和呈现的字符串,并且不会执行自动响应。

res.render('index', function (err, html) {
  // ...
})

res.render('user', { name: 'Tobi' }, function (err, html) {
  // ...
})

res.req

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

中间件

basicAuth()

基本身份验证中间件,使用用户名填充 req.user

简单的用户名和密码

app.use(express.basicAuth('username', 'password'))

回调验证

app.use(express.basicAuth(function (user, pass) {
  return user === 'tj' && pass === 'wahoo'
}))

异步回调验证,接受 fn(err, user),在这种情况下,req.user 将是传递的用户对象。

app.use(express.basicAuth(function (user, pass, fn) {
  User.authenticate({ user: user, pass: pass }, fn)
}))

bodyParser()

支持 JSON、urlencoded 和 multipart 请求的请求正文解析中间件。此中间件只是 json()urlencoded()multipart() 中间件的包装器。

app.use(express.bodyParser())

// is equivalent to:
app.use(express.json())
app.use(express.urlencoded())
app.use(express.multipart())

出于安全考虑,如果您的应用程序不需要文件上传,最好禁用它。要执行此操作,请仅使用所需的中间件,即不要使用 bodyParsermultipart() 中间件

app.use(express.json())
app.use(express.urlencoded())

如果您的应用程序需要文件上传,您应该设置 处理这些文件的策略

compress()

使用 gzip / deflate 压缩响应数据。此中间件应置于堆栈中“较高”的位置,以确保可以压缩所有响应。

app.use(express.logger())
app.use(express.compress())
app.use(express.methodOverride())
app.use(express.bodyParser())

cookieParser()

解析 Cookie 头字段,并使用以 cookie 名称作为键的对象填充 req.cookies。您还可以选择通过传递 secret 字符串启用签名 cookie 支持。

app.use(express.cookieParser())
app.use(express.cookieParser('some secret'))

cookieSession()

提供基于 cookie 的会话,并填充 req.session。此中间件采用以下选项

  • key cookie 名称,默认为 connect.sess
  • secret 防止 cookie 篡改
  • cookie 会话 cookie 设置,默认为 { path: '/', httpOnly: true, maxAge: null }
  • proxy 在设置安全 cookie(通过“x-forwarded-proto”)时信任反向代理
app.use(express.cookieSession())

要清除 cookie,只需在响应之前将会话分配为 null

req.session = null

csrf()

CSRF 保护中间件。

默认情况下,此中间件会生成一个名为“_csrf”的令牌,该令牌应添加到更改状态的请求中,在隐藏表单字段、查询字符串等中。此令牌针对 req.csrfToken() 验证。

默认的 value 函数检查由 bodyParser() 中间件生成的 req.body、由 query() 生成的 req.query 和“X-CSRF-Token”头字段。

此中间件需要会话支持,因此应添加到 session() 下方的某个位置。

directory()

目录服务中间件,提供给定的 path。此中间件可以与 static() 配对以提供文件,提供全功能的文件浏览器。

app.use(express.directory('public'))
app.use(express.static('public'))

此中间件接受以下选项

  • hidden 显示隐藏(点)文件。默认为 false。
  • icons 显示图标。默认为 false。
  • filter 将此过滤器函数应用于文件。默认为 false。