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 查看我的个人动态。

Fastify 系列教程二 (中间件、钩子函数和装饰器)的更多相关文章

  1. Fastify 系列教程二 (中间件、钩子函数和装饰器)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) 中间件 Fastify 提供了与 Express 和 Restify ...

  2. 【Flask】 python学习第一章 - 4.0 钩子函数和装饰器路由实现 session-cookie 请求上下文

    钩子函数和装饰器路由实现 before_request 每次请求都会触发 before_first_requrest  第一次请求前触发 after_request  请求后触发 并返回参数 tear ...

  3. python---基础知识回顾(二)(闭包函数和装饰器)

    一.闭包函数: 闭包函数: 1.在一个外函数中定义了一个内函数 2.内函数里运用了外函数的临时变量,而不是全局变量 3.并且外函数的返回值是内函数的引用.(函数名,内存块地址,函数名指针..) 正确形 ...

  4. Fastify 系列教程一(路由和日志)

    介绍 Fastify是一个高度专注于以最少开销和强大的插件架构,为开发人员提供最佳体验的Web框架. 它受到了 Hapi 和 Express 的启发,是目前最快的 Node 框架之一. Fastify ...

  5. Fastify 系列教程三 (验证、序列化和生命周期)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) 验证 Fast ...

  6. Fastify 系列教程四 (求对象、响应对象和插件)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...

  7. Fastify 系列教程一 (路由和日志)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...

  8. CRL快速开发框架系列教程二(基于Lambda表达式查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. NGUI系列教程二

    接下来我们创建一个Label,NGUI->Open the Widget Wizard,打开widgetTool对话框,在Template中选择Label,确定AddTo右侧选项为panel,点 ...

随机推荐

  1. 面对对象编程(OOP, Object Oriented Programming)及其三个基本特性

    一千个读者,一千个哈姆雷特.对于面对对象编程,书上都会告诉我们它有三个基本特性,封装,继承,多态,但谈起对这三点的见解,又是仁者见仁智者见智,感觉还是得多去编程中体验把 . 面向对象编程(OOP, O ...

  2. 从getwebshell到绕过安全狗云锁提权再到利用matasploit进服务器

    本文作者:i春秋签约作家——酷帥王子 一. 利用getwebshell篇 首先对目标站进行扫描,发现是asp的,直接扫出网站后台和默认数据库,下载解密登陆如图: 下面进后台发现有fckeditor,而 ...

  3. day 17python 面对对象之继承

    一:什么面向对象的继承? 比较官方的说法就是: 继承(英语:inheritance)是面向对象软件技术当中的一个概念.如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A ...

  4. pythonweb框架Flask学习笔记02-一个简单的小程序

    #-*- coding:utf-8 -*- #导入了Flask类 这个类的实例将会是我们的WSGI应用程序 from flask import Flask #创建一个Flask类的实例 第一个参数是应 ...

  5. cobbler 自定义安装系统

    1.自定义安装系统(根据mac地址)--name=定义名称--mac=客户端的mac地址--ip-address=需求的ip--subnet=掩码 --gateway=网关--interface=网口 ...

  6. jade直接写类似JavaScript语法的东西,不需要写script

    我们知道,html做计算都是在JavaScript中完成的,那么不用JavaScript行不行呢,可以直接在jade中一样的编写 如: -var a = 3 -var b = 4 div a+b = ...

  7. windows 安装openssl

    参考文章:http://www.cnblogs.com/tangxin-blog/p/5724071.html 准备条件: 1.VS2012 (携带c++) 2.下载openssl 源码 3.安装Pe ...

  8. 使用mysqldump备份单表数据,并使用navicat导出单表中部分字段到excel

    今天工作上遇到一个问题,客户需要将生产环境上数据库中用户表中的用户名.登录名.邮箱三个字段导出到excel中,查了一下,分两个步骤完成了任务 1. 使用mysqldump命令将生产环境的user表备份 ...

  9. 第6章—渲染web视图—使用Thymeleaf

    使用Thymeleaf 长期以来,jsp在视图领域有非常重要的地位,随着时间的变迁,出现了一位新的挑战者:Thymeleaf,Thymeleaf是原生的,不依赖于标签库.它能够在接受原始HTML的地方 ...

  10. java数据结构之递归算法

    概述程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中广泛应用.递归有直接递归和间接递归•直接递归:函数在执行过程中调用本身.•间接递归:函数在执行过程中调用其它 ...