Fastify 系列教程:
- Fastify 系列教程一 (路由和日志)
- Fastify 系列教程二 (中間件、鈎子函數和裝飾器)
- Fastify 系列教程三 (驗證、序列化和生命周期)
- Fastify 系列教程四 (請求對象、響應對象和插件)
中間件
Fastify 提供了與 Express 和 Restify 中間件兼容的異步中間件引擎。
所以,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 的
req
和res
,而路由中的request
和reply
是經過 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)
注意 req
、res
和 request
、reply
的區別。
參數 | 描述 |
---|---|
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 查看我的個人動態。