Fastify 系列教程二 (中間件、鈎子函數和裝飾器)


Fastify 系列教程:

中間件

Fastify 提供了與 ExpressRestify 中間件兼容的異步中間件引擎

所以,Fastify 可以使用 Express 中間件

注意:Fastify 中沒有錯誤處理中間件(err, req, res, next)。如果需要處理中間件中的錯誤時,只需要調用 next(new Error('error message')) 即可,Fastify 會為你關閉請求並發送錯誤響應。

示例:

訪問靜態資源

配置 serve-static 訪問靜態資源。

目錄結構:

public
   |-css
   |-js
      |-jquery.js
   |-images
views
app.js

app.js:

const serveStatic = require('serve-static')
const path = require('path')

fastify.use('/public', serveStatic(path.resolve(__dirname, 'public')))

此時,訪問 localhost:3030/public/js/jquery.js 可以正確獲得靜態資源文件。

注意:中間件的請求和響應參數是原生 Nodejs Http 的 reqres,而路由中的 requestreply 是經過 Fastify 封裝的,兩者並不一樣:

const fastify = require('fastify')()

fastify.use(function(req, res, next){
  req.hello = "req.hello"
  res.hello = "res.hello"
  next()
})

fastify.use(function(req, res, next){
  console.log('middle:', req.hello)
  console.log('middle:', res.hello)
  next()
})

fastify.get('/', function (request, reply) {
  console.log('route:', request.hello)
  console.log('route:', reply.hello)
  reply.send({ hello: 'world' })
})
/*
middle: req.hello
middle: res.hello
route: undefined
route: undefined
*/

鈎子函數

Fastify 中共有四個應用級鈎子和一個路由級鈎子。

四個應用級鈎子:

  • onRequest(req, res, next)
  • preHandler(request, reply, next)
  • onResponse(res, next)
  • onClose(instance, done)

一個路由級鈎子:

  • beforeHandler(request, reply, done)

注意 reqresrequestreply 的區別。

參數 描述
req Node.js Http 請求對象
res Node.js Http 響應對象
request Fastify Request 接口
reply Fastify Reply 接口
next 繼續下一個 生命周期 任務

使用 addHook 方法添加鈎子函數:

fastify.addHook('onRequest', (req, res, next) => {
  // some code
  next()
})

fastify.addHook('preHandler', (request, reply, next) => {
  // some code
  next()
})

fastify.addHook('onResponse', (res, next) => {
  // some code
  next()
})

如果在執行鈎子函數時遇到錯誤,只需將其傳遞給 next(),並且 Fastify 將自動關閉請求並向用戶發送相應的錯誤代碼。

fastify.addHook('onRequest', (req, res, next) => {
next(new Error('some error'))
})

如果你希望傳遞一個自定義狀態碼,可以使用reply.code():

fastify.addHook('preHandler', (request, reply, next) => {
reply.code(500)
next(new Error('some error'))
})

onClose

onClose 是唯一不在生命周期中的鈎子,當調用 fastify.close() 來停止服務器時,會觸發此鈎子,第一個參數是 Fastify 實例,第二個用來完成回調。

const fastify = require('fastify')()

fastify.get('/close', function(request, reply){
  reply.type('text/html').send('<h1>Close Server</h1>')
  fastify.close()
})

fastify.onClose(function(instance, done){
  console.log('close db connection')
  done()
})

訪問 /close 時頁面會顯示 Close Server,並且控制台會輸出:

[Running] node "/Users/lavyun/Code/node/learn-fastify/app.js"
close db connection

[Done] exited with code=0 in 8.524 seconds

在關閉數據庫鏈連接之后,app.js 也被 exit 了。

preHandler 和 beforeHandler

preHandler 的受眾對象是所有的路由,而 beforeHandler 的受眾對象是某個特定的路由,另外,beforeHandler 總是在 preHandler 之后執行。

fastify.addHook('preHandler', (request, reply, done) => {
  console.log('preHandler')
  done()
})

fastify.get('/', {
  beforeHandler: function (request, reply, done) {
    console.log('beforeHandler')
    done()
  }
}, function (request, reply) {
  reply.send({ hello: 'world' })
})

// preHandler
// beforeHandler

beforeHandler 也可以是一個函數數組:

fastify.addHook('preHandler', (request, reply, done) => {
  console.log('preHandler')
  done()
})

const firstBeforeHandler = (request, reply, done) => {
  console.log('first beforeHandler')
  done()
}

const secondBeforeHandler = (request, reply, done) => {
  console.log('second beforeHandler')
  done()
}

fastify.get('/', {
  beforeHandler: [firstBeforeHandler, secondBeforeHandler]
}, function (request, reply) {
  reply.send({ hello: 'world' })
})

// preHandler
// first beforeHandler
// second beforeHandler

裝飾器

如果想為 Fastify 實例添加功能,可以使用 decorate 方法。

decorate 允許向 Fastify 實例添加新屬性。可以是一個值、一個函數,也可以是一個對象或一個字符串等。

使用方法

decorate

只需要調用 decorate 函數,並且傳入新屬性的鍵和值即可。

fastify.decorate('utility', () => {
// something very useful
})

也可以定義其他類型的實例:

fastify.decorate('conf', {
  db: 'some.db',
  port: 3000
})

一旦定義了這個實例,可以通過傳入的參數名稱來得到該值:

fastify.utility()

console.log(fastify.conf.db)

裝飾器不可以重新被覆蓋,如果要定義一個已經存在的裝飾器,decorate 將會拋出異常。

fastify.decorate("d1", 'd1')
fastify.decorate("d1", "d2") // Error

decorateReply

decorateReply 可以為 Reply 對象添加新屬性。

fastify.decorateReply('utility', function () {
// something very useful
})

decorateRequest

decorateRequest 可以為 Request 對象添加新屬性。

fastify.decorateRequest('utility', function () {
// something very useful
})

extendServerError

如果要擴展 服務器錯誤,可以使用此 API,必須傳入一個返回值為對象的函數,該函數將接收原始的 Error 對象,並返回新Error 對象來擴展服務器錯誤。

fastify.extendServerError((err) => {
  return {
    timestamp: new Date()
  }
})

/*
最終的錯誤對象格式:
{
  error: String
  message: String
  statusCode: Number
  timestamp: Date
}
*/

依賴

如果一個裝飾器依賴於另一個裝飾器,可以將其他裝飾器聲明為依賴。只需要添加一個字符串數組(表示所依賴的裝飾器的名稱)作為第三個參數即可:

fastify.decorate('utility', fn, ['greet', 'log'])

如果不滿足依賴關系,那么 decorate 會拋出一個異常,但是不用擔心:依賴關系檢查會在服務器啟動之前執行,所以在運行時不會發生錯誤。

hasDecorator

可以使用 hasDecorator 檢查裝飾器是否存在:

fastify.hasDecorator('utility')

Fastify 的更多使用將在接下來的博客中說明。

Tips:

訪問 https://lavyun.gitbooks.io/fastify/content/ 查看我翻譯的 Fastify 中文文檔。

訪問 lavyun.cn 查看我的個人動態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM