Fastify 回復(fù)

2020-02-06 15:41 更新

回復(fù)

簡介

處理函數(shù)的第二個參數(shù)為 Reply。 Reply 是 Fastify 的一個核心對象。它暴露了以下函數(shù)及屬性:

  • .code(statusCode) - 設(shè)置狀態(tài)碼。
  • .status(statusCode) - .code(statusCode) 的別名。
  • .statusCode - 獲取或設(shè)置 HTTP 狀態(tài)碼。
  • .header(name, value) - 設(shè)置響應(yīng) header。
  • .getHeader(name) - 獲取某個 header 的值。
  • .removeHeader(key) - 清除已設(shè)置的 header 的值。
  • .hasHeader(name) - 檢查某個 header 是否設(shè)置。
  • .type(value) - 設(shè)置 Content-Type header。
  • .redirect([code,] url) - 重定向至指定的 url,狀態(tài)碼可選 (默認為 302)。
  • .callNotFound() - 調(diào)用自定義的 not found 處理函數(shù)。
  • .serialize(payload) - 使用默認的或自定義的 json 序列化工具序列化指定的 payload,并返回處理后的結(jié)果。
  • .serializer(function) - 設(shè)置自定義的 payload 序列化工具。
  • .send(payload) - 向用戶發(fā)送 payload。類型可以是純文本、buffer、JSON、stream,或一個 Error 對象。
  • .sent - 一個 boolean,檢查 send 是否已被調(diào)用。
  • .res - Node 原生的 http.ServerResponse 對象。
  • .log - 請求的日志實例。
  • .request - 請求。
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)

如果沒有設(shè)置 reply.code,statusCode 會是 200。

.statusCode

獲取或設(shè)置 HTTP 狀態(tài)碼。作為 setter 使用時,是 reply.code() 的別名。

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

.header(key, value)

設(shè)置響應(yīng) header。如果值被省略或為 undefined,將被強制設(shè)成 ''。

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

.getHeader(key)

獲取已設(shè)置的 header 的值。

reply.header('x-foo', 'foo') // 設(shè)置 x-foo header 的值為 foo
reply.getHeader('x-foo') // 'foo'

.removeHeader(key)

清除已設(shè)置的 header 的值。

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

.hasHeader(key)

返回一個 boolean,用于檢查是否設(shè)置了某個 header。

.redirect(dest)

重定向請求至指定的 url,狀態(tài)碼可選,當(dāng)未通過 code 方法設(shè)置時,默認為 302。

reply.redirect('/home')

.callNotFound()

調(diào)用自定義的 not found 處理函數(shù)。

reply.callNotFound()

.getResponseTime()

調(diào)用自定義響應(yīng)時間獲取函數(shù),來計算自收到請求起的時間。

const milliseconds = reply.getResponseTime()

.type(contentType, type)

設(shè)置響應(yīng)的 content type。 這是 reply.header('Content-Type', 'the/type') 的簡寫。

reply.type('text/html')

.serializer(func)

.send() 方法會默認將 Buffer、stream、string、undefined、Error 之外類型的值 JSON-序列化。假如你需要在特定的請求上使用自定義的序列化工具,你可以通過 .serializer() 來實現(xiàn)。要注意的是,如果使用了自定義的序列化工具,你必須同時設(shè)置 'Content-Type' header。

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

注意,你并不需要在一個 handler 內(nèi)部使用這一工具,因為 Buffers、streams 以及字符串 (除非已經(jīng)設(shè)置了序列化工具) 被認為是已序列化過的。

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

請看 .send() 了解更多關(guān)于發(fā)送不同類型值的信息。

.sent

如你所見,.sent 屬性表明是否已通過 reply.send() 發(fā)送了一個響應(yīng)。

當(dāng)控制器是一個 async 函數(shù)或返回一個 promise 時,可以手動設(shè)置 reply.sent = true,以防 promise resolve 時自動調(diào)用 reply.send()。通過設(shè)置 reply.sent = true,程序能完全掌控底層的請求,且相關(guān)鉤子不會被觸發(fā)。

請看范例:

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

  return Promise.resolve('this will be skipped') // 譯注:該處會被跳過
})

如果處理函數(shù) reject,將會記錄一個錯誤。

.send(data)

顧名思義,.send() 是向用戶發(fā)送 payload 的函數(shù)。

對象

如上文所述,如果你發(fā)送 JSON 對象時,設(shè)置了輸出的 schema,那么 send 會使用 fast-json-stringify 來序列化對象。否則,將使用 JSON.stringify()。

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

字符串

在未設(shè)置 Content-Type 的時候,字符串會以 text/plain; charset=utf-8 類型發(fā)送。如果設(shè)置了 Content-Type,且使用自定義序列化工具,那么 send 發(fā)出的字符串會被序列化。否則,字符串不會有任何改動 (除非 Content-Type 的值為 application/json; charset=utf-8,這時,字符串會像對象一樣被 JSON-序列化,正如上一節(jié)所述)。

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

Streams

send 開箱即用地支持 stream。它使用 pump 來避免文件描述符 (file descriptors) 的泄露。如果在未設(shè)置 'Content-Type' header 的情況下發(fā)送 stream,它會被設(shè)定為 'application/octet-stream'。

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

Buffers

未設(shè)置 'Content-Type' header 的情況下發(fā)送 buffer,send 會將其設(shè)置為 '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 發(fā)送一個 Error 的實例,F(xiàn)astify 會自動創(chuàng)建一個如下的錯誤結(jié)構(gòu):

{
  error: String        // http 錯誤信息
  code: String         // Fastify 的錯誤代碼
  message: String      // 用戶錯誤信息
  statusCode: Number   // http 狀態(tài)碼
}

你可以向 Error 對象添加自定義屬性,例如 headers,這可以用來增強 http 響應(yīng)。注意:如果 send 一個錯誤,但狀態(tài)碼小于 400,F(xiàn)astify 會自動將其設(shè)為 500。

貼士:你可以通過 http-errors 或 fastify-sensible 來簡化生成的錯誤:

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

如果你想完全自定義錯誤處理,請看 setErrorHandler API。注:當(dāng)自定義錯誤處理時,你需要自行記錄日志

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 的類型

發(fā)送的 payload (序列化之后、經(jīng)過任意的 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 默認發(fā)送 500 狀態(tài)碼。要修改回復(fù),可以 reject 一個 promise,或在 async 函數(shù) 中進行 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
})

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

.then(fullfilled, rejected)

顧名思義,Reply 對象能被等待。換句話說,await reply 將會等待,直到回復(fù)被發(fā)送。 如上的 await 語法調(diào)用了 reply.then()。

reply.then(fullfilled, rejected) 接受兩個參數(shù):

  • fullfilled 會在響應(yīng)完全發(fā)送后被調(diào)用。
  • rejected 會在底層的 stream 出現(xiàn)錯誤時被調(diào)用。例如,socket 連接被破壞時。

更多細節(jié),請看:


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號