2022-11-11 来源:华纳网 责任编辑:谷雨老师 人气:
核心提示:大家好,欢迎来到谷雨课堂 Request 处理函数的第一个参数是 Request . Request 是 Fastify 的核心对象,包含了以下字段: query - 解析后的 querystring,其格式由 querystringParser 指定。 body - 消息主体 params - URL 参数 headers - header 的 getter
大家好,欢迎来到谷雨课堂


Request

处理函数的第一个参数是 Request.
Request 是 Fastify 的核心对象,包含了以下字段:

  • query - 解析后的 querystring,其格式由 querystringParser 指定。

  • body - 消息主体

  • params - URL 参数

  • headers - header 的 getter 与 setter

  • raw - Node 原生的 HTTP 请求

  • req (不推荐,请使用 .raw) - Node 原生的 HTTP 请求

  • server - Fastify 服务器的实例,以当前的封装上下文为作用域。

  • id - 请求 ID

  • log - 请求的日志实例

  • ip - 请求方的 ip 地址

  • ips - x-forwarder-for header 中保存的请求源 ip 数组,按访问先后排序 (仅当 trustProxy 开启时有效)

  • hostname - 请求方的主机名 (当 trustProxy 启用时,从 X-Forwarded-Host header 中获取)。为了兼容 HTTP/2,当没有相关 header 存在时,将返回 :authority

  • protocol - 请求协议 (https 或 http)

  • method - 请求方法

  • url - 请求路径

  • routerMethod - 处理请求的路由函数

  • routerPath - 处理请求的路由的匹配模式

  • is404 - 当请求被 404 处理时为 true,反之为 false

  • connection - 不推荐,请使用 socket。请求的底层连接

  • socket - 请求的底层连接

  • context - Fastify 内建的对象。你不应该直接使用或修改它,但可以访问它的下列特殊属性:

    • context.config - 路由 config 对象。

¶Headers

request.headers 返回来访请求的 header 对象。你也可以如下设置自定义的 header:

request.headers = {
  'foo': 'bar',
  'baz': 'qux'
}

该操作能向请求 header 添加新的值,且该值能通过 request.headers.bar 读取。此外,request.raw.headers 能让你访问标准的请求 header。

fastify.post('/:params', options, function (request, reply) {
  console.log(request.body)
  console.log(request.query)
  console.log(request.params)
  console.log(request.headers)
  console.log(request.raw)
  console.log(request.server)
  console.log(request.id)
  console.log(request.ip)
  console.log(request.ips)
  console.log(request.hostname)
  console.log(request.protocol)
  console.log(request.url)
  console.log(request.routerMethod)
  console.log(request.routerPath)
  request.log.info('some info')
})
 

处理函数的第二个参数为 Reply。Reply 是 Fastify 的一个核心对象。它暴露了以下函数及属性:

  • .code(statusCode) - 设置状态码。

  • .status(statusCode) - .code(statusCode) 的别名。

  • .server - Fastify 实例的引用。

  • .statusCode - 获取或设置 HTTP 状态码。

  • .header(name, value) - 设置响应 header。

  • .getHeader(name) - 获取某个 header 的值。

  • .removeHeader(key) - 清除已设置的 header 的值。

  • .hasHeader(name) - 检查某个 header 是否设置。

  • .type(value) - 设置 Content-Type header。

  • .redirect([code,] dest) - 重定向至指定的 url,状态码可选 (默认为 302)。

  • .callNotFound() - 调用自定义的 not found 处理函数。

  • .serialize(payload) - 使用默认的或自定义的 JSON 序列化工具序列化指定的 payload,并返回处理后的结果。

  • .serializer(function) - 设置自定义的 payload 序列化工具。

  • .send(payload) - 向用户发送 payload。类型可以是纯文本、buffer、JSON、stream,或一个 Error 对象。

  • .sent - 一个 boolean,检查 send 是否已被调用。

  • .raw - Node 原生的 http.ServerResponse 对象。

  • .res (不推荐,请使用 .raw) - Node 原生的 http.ServerResponse 对象。

  • .log - 请求的日志实例。

  • .request - 请求。

  • .context - 请求的 context 属性。

fastify.get('/', options, function (request, reply) {
  // 你的代码
  reply
    .code(200)
    .header('Content-Type', 'application/json; charset=utf-8')
    .send({ hello: 'world' })
})

另外,Reply 能够访问请求的上下文:

fastify.get('/', {config: {foo: 'bar'}}, function (request, reply) {
  reply.send('handler config.foo = ' + reply.context.config.foo)
})

 

¶.code(statusCode)

如果没有设置 reply.codestatusCode 会是 200

 

¶.statusCode

获取或设置 HTTP 状态码。作为 setter 使用时,是 reply.code() 的别名。

if (reply.statusCode >= 299) {
  reply.statusCode = 500
}

 

¶.server

Fastify 服务器的实例,以当前的封装上下文为作用域。

fastify.decorate('util', function util () {
  return 'foo'
})
fastify.get('/', async function (req, rep) {
  return rep.server.util() // foo
})

 

¶.header(key, value)

设置响应 header。如果值被省略或为 undefined,将被强制设成 ''

更多信息,请看 http.ServerResponse#setHeader

 

¶.getHeader(key)

获取已设置的 header 的值。

reply.header('x-foo', 'foo') // 设置 x-foo header 的值为 foo
reply.getHeader('x-foo') // 'foo'

 

¶.removeHeader(key)

清除已设置的 header 的值。

reply.header('x-foo', 'foo')
reply.removeHeader('x-foo')
reply.getHeader('x-foo') // undefined

 

¶.hasHeader(key)

返回一个 boolean,用于检查是否设置了某个 header。

 

¶.redirect([code ,] dest)

重定向请求至指定的 URL,状态码可选,当未通过 code 方法设置时,默认为 302

示例 (不调用 reply.code()):状态码 302,重定向至 /home

reply.redirect('/home')

示例 (不调用 reply.code()):状态码 303,重定向至 /home

reply.redirect(303, '/home')

示例 (调用 reply.code()):状态码 303,重定向至 /home

reply.code(303).redirect('/home')

示例 (调用 reply.code()):状态码 302,重定向至 /home

reply.code(303).redirect(302, '/home')

 

¶.callNotFound()

调用自定义的 not found 处理函数。注意,只有在 setNotFoundHandler 中指明的 preHandler 钩子会被调用。

reply.callNotFound()

 

¶.getResponseTime()

调用自定义响应时间获取函数,来计算自收到请求起的时间。

const milliseconds = reply.getResponseTime()

 

¶.type(contentType, type)

设置响应的 content type。这是 reply.header('Content-Type', 'the/type') 的简写。

reply.type('text/html')

如果 Content-Type 为 JSON 子类型,并且未设置 charset 参数,则使用 utf-8 作为 charset 的默认参数。

 

¶.serializer(func)

.send() 方法会默认将 BufferstreamstringundefinedError 之外类型的值 JSON-序列化。假如你需要在特定的请求上使用自定义的序列化工具,你可以通过 .serializer() 来实现。要注意的是,如果使用了自定义的序列化工具,你必须同时设置 'Content-Type' header。

reply
  .header('Content-Type', 'application/x-protobuf')
  .serializer(protoBuf.serialize)

注意,你并不需要在一个 handler 内部使用这一工具,因为 Buffers、streams 以及字符串 (除非已经设置了序列化工具) 被认为是已序列化过的。

reply
  .header('Content-Type', 'application/x-protobuf')
  .send(protoBuf.serialize(data))

请看 .send() 了解更多关于发送不同类型值的信息。

 

¶.raw

Node 核心的 http.ServerResponse 对象。使用 Reply.raw 上的方法会跳过 Fastify 对 HTTP 响应的处理逻辑,所以请谨慎使用。以下是一个例子:

app.get('/cookie-2', (req, reply) => {
  reply.setCookie('session', 'value', { secure: false }) // 这行不会应用

  // 在这个例子里我们只使用了 nodejs 的 http 响应对象
  reply.raw.writeHead(200, { 'Content-Type': 'text/plain' })
  reply.raw.write('ok')
  reply.raw.end()
})

在《回复》里有另一个误用 Reply.raw 的例子。

 

¶.sent

如你所见,.sent 属性表明是否已通过 reply.send() 发送了一个响应。

当控制器是一个 async 函数或返回一个 promise 时,可以手动设置 reply.sent = true,以防 promise resolve 时自动调用 reply.send()。通过设置 reply.sent = true,程序能完全掌控底层的请求,且相关钩子不会被触发。

请看范例:

app.get('/', (req, reply) => {
  reply.sent = true
  reply.raw.end('hello world')

  return Promise.resolve('this will be skipped') // 译注:该处会被跳过
})

如果处理函数 reject,将会记录一个错误。

 

¶.hijack()

有时你需要终止请求生命周期的执行,并手动发送响应。

Fastify 提供了 reply.hijack() 方法来完成此任务。在 reply.send() 之前的任意节点调用该方法,能阻止 Fastify 自动发送响应,并不再执行之后的生命周期函数 (包括用户编写的处理函数)。

特别注意 (*):假如使用了 reply.raw 来发送响应,则 onResponse 依旧会执行。

 

¶.send(data)

顾名思义,.send() 是向用户发送 payload 的函数。

 

¶对象

如上文所述,如果你发送 JSON 对象时,设置了输出的 schema,那么 send 会使用 fast-json-stringify 来序列化对象。否则,将使用 JSON.stringify()

fastify.get('/json', options, function (request, reply) {
  reply.send({ hello: 'world' })
})

 

¶字符串

在未设置 Content-Type 的时候,字符串会以 text/plain; charset=utf-8 类型发送。如果设置了 Content-Type,且使用自定义序列化工具,那么 send 发出的字符串会被序列化。否则,字符串不会有任何改动 (除非 Content-Type 的值为 application/json; charset=utf-8,这时,字符串会像对象一样被 JSON-序列化,正如上一节所述)。

fastify.get('/json', options, function (request, reply) {
  reply.send('plain string')
})

 

¶Streams

send 开箱即用地支持 stream。如果在未设置 'Content-Type' header 的情况下发送 stream,它会被设定为 'application/octet-stream'

fastify.get('/streams', function (request, reply) {
  const fs = require('fs')
  const stream = fs.createReadStream('some-file', 'utf8')
  reply.send(stream)
})

 

¶Buffers

未设置 'Content-Type' header 的情况下发送 buffer,send 会将其设置为 'application/octet-stream'

const fs = require('fs')
fastify.get('/streams', function (request, reply) {
  fs.readFile('some-file', (err, fileBuffer) => {
    reply.send(err || fileBuffer)
  })
})

 

¶Errors

若使用 send 发送一个 Error 的实例,Fastify 会自动创建一个如下的错误结构:

{
  error: String        // HTTP 错误信息
  code: String         // Fastify 的错误代码
  message: String      // 用户错误信息
  statusCode: Number   // HTTP 状态码
}

你可以向 Error 对象添加自定义属性,例如 headers,这可以用来增强 HTTP 响应。
注意:如果 send 一个错误,但状态码小于 400,Fastify 会自动将其设为 500。

贴士:你可以通过 http-errors 或 fastify-sensible 来简化生成的错误:

fastify.get('/', function (request, reply) {
  reply.send(httpErrors.Gone())
})

你可以通过如下方式自定义 JSON 错误的输出:

  • 为自定义状态码设置响应 JSON schema。

  • 为 Error 实例添加额外属性。

请注意,如果返回的状态码不在响应 schema 列表里,那么默认行为将被应用。

fastify.get('/', {
  schema: {
    response: {
      501: {
        type: 'object',
        properties: {
          statusCode: { type: 'number' },
          code: { type: 'string' },
          error: { type: 'string' },
          message: { type: 'string' },
          time: { type: 'string' }
        }
      }
    }
  }
}, function (request, reply) {
  const error = new Error('This endpoint has not been implemented')
  error.time = 'it will be implemented in two weeks'
  reply.code(501).send(error)
})

如果你想自定义错误处理,请看 setErrorHandler API。
注:当自定义错误处理时,你需要自行记录日志

API:

fastify.setErrorHandler(function (error, request, reply) {
  request.log.warn(error)
  var statusCode = error.statusCode >= 400 ? error.statusCode : 500
  reply
    .code(statusCode)
    .type('text/plain')
    .send(statusCode >= 500 ? 'Internal server error' : error.message)
})

路由生成的 not found 错误会使用 setNotFoundHandler。API:

fastify.setNotFoundHandler(function (request, reply) {
  reply
    .code(404)
    .type('text/plain')
    .send('a custom not found')
})

 

¶最终 payload 的类型

发送的 payload (序列化之后、经过任意的 onSend 钩子) 必须为下列类型之一,否则将会抛出一个错误:

  • string

  • Buffer

  • stream

  • undefined

  • null

 

¶Async-Await 与 Promise

Fastify 原生地处理 promise 并支持 async-await。
请注意,在下面的例子中我们没有使用 reply.send。

const delay = promisify(setTimeout)

fastify.get('/promises', options, function (request, reply) {
  return delay(200).then(() => { return { hello: 'world' }})
})

fastify.get('/async-await', options, async function (request, reply) {
  await delay(200)
  return { hello: 'world' }
})

被 reject 的 promise 默认发送 500 状态码。要修改回复,可以 reject 一个 promise,或在 async 函数 中进行 throw 操作,同时附带一个有 statusCode (或 status) 与 message 属性的对象。

fastify.get('/teapot', async function (request, reply) {
  const err = new Error()
  err.statusCode = 418
  err.message = 'short and stout'
  throw err
})

fastify.get('/botnet', async function (request, reply) {
  throw { statusCode: 418, message: 'short and stout' }
  // 这一 json 对象将被发送给客户端
})

想要了解更多?请看 Routes#async-await。

 

完整的源代码可以登录【华纳网】下载。
https://www.worldwarner.com/






 





免责声明:本文仅代表作者个人观点,与华纳网无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。