Fastify 系列教程:

响应对象

路由的第二个参数即是响应对象 reply ,它有如下几个方法:

  • .code(statusCode) - 设置状态码。
  • .header(name, value) - 设置响应头。
  • .type(value) - 设置 Content-Type 字段。
  • .redirect([code,] url) - 重定向到特定的地址,code 参数是可选的 (默认为 302)。
  • .serializer(function) - 为有效荷载设置自定义的序列化器。
  • .send(payload) - 向客户端发送荷载,可以是文本、JSON、流或者一个错误对象。
  • .sent - 一个布尔值,用来判断 send 函数是否已经被调用。

示例:

fastify.get('/', options, function (request, reply) {
// Your code
reply
.code(200)
.header('Content-Type', 'application/json')
.send({ hello: 'world' })
})

Code

如果没有设置 reply.code,默认 statusCode 是 200。

Header设置响应头

设置自定义的响应头。

如果没有设置 'Content-Type' 字段,Fastify 猜测你会使用 'application/json', 除非你要发送一个流, 在这种情况下,Fastify会识别并设置 'Content-Type''application/octet-stream'。

注意,如果使用的序列化器不是序列化到 JSON,则必须设置自定义的 Content-Type 头。

Redirect

重定向一个请求到特定的地址,状态码是可选的,默认为 302。

reply.redirect('/home')

Type

设置响应头的 Content-Type字段。

这是 reply.header('Content-Type', 'the/type') 的简写。

reply.type('text/html')

Serializer

Fastify 作为一个完整的JSON兼容服务器而诞生,所以可以直接序列化 send() 函数中的有效荷载。如果你设置了输出 schema,那么会使用 fast-json-stringify 作为格式化JSON的工具包,否则使用fast-safe-stringify

如果想使用自定义的序列化器,比如 msgpack5 或者 protobuf,你可以使用 .serializer() ,注意:如果使用自定义的序列化器却不是序列化成JSON,那么必须得设置自定义的 'Content-Type' 头。

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

Promises

发送原生的 promises 和支持开箱即用的 async-await

fastify.get('/promises', options, function (request, reply) {
const promise = new Promise(function(){
setTimeout(function(resolve, reject){
resolve({hello: 'promise'})
}, 1000)
})
reply
.code(200)
.send(promise)
}) // 上述代码将会在服务端延迟 1s 后成功响应 {hello: 'promise'} fastify.get('/async-await', options, async function (request, reply) {
var res = await new Promise(function (resolve) {
setTimeout(resolve, 200, { hello: 'world' })
})
return res
})

Streams

也可以发送流,内部使用 pump 来避免文件描述符的泄露。如果你要发送流,并且尚未设置 “Content-Type” 头,则 send 将会以“application/octet-stream” 进行设置。

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

Errors

如果你向 send 函数传入一个 Error 对象的实例,Fastify 将自动创建一个结构如下的错误

{
error: String // the http error message
message: String // the user error message
statusCode: Number // the http status code
}
fastify.get('/error', function(request. reply){
reply.send(new Error('error request'))
})

如果你想要扩展错误对象,可以使用 extendServerError

如果你传入错误对象并且设置小于 400 的状态码,Fastify 将会自动的设置成 500。

请求对象

路由的第一个参数即是请求对象 request,它有如下几个属性:

  • query - 解析后的查询字符串
  • body - 请求体
  • params - 匹配url的参数,例如: 用 /page/5 匹配 /page/:id => {id: 5}
  • headers - 请求头对象
  • req - 原生Node的请求对象
  • log - 日志记录器的实例
fastify.post('/page/:id', options, function (request, reply) {
console.log(request.body)
console.log(request.query)
console.log(request.params)
console.log(request.headers)
console.log(request.req)
request.log.info('some info')
})

插件

Fastify 允许用户使用插件扩展其功能。

一个插件可以是一组路由,一个装饰器等,可以使用 register 函数注册插件。

默认情况下,register 创建了一个新的作用域,这意味着如果对 Fastify 实例(通过 decorate)进行一些更改,则此更改不会反映到当前上下文的祖先中,而只会反映到其子节点。这个特性允许我们实现插件封装和继承,这样就创建了一个直接非循环图(DAG),就不会有交叉依赖关系引起的问题。

创建一个插件

创建插件非常简单,你只要创建一个包含三个参数的方法。第一个是 fastify 实例,第二个是一个配置对象,最后一个是 next 回调。

// plugin.js
module.exports = function (fastify, opts, next) {
fastify.decorate('utility', () => {}) fastify.get('/', handler) next()
}

使用插件:

var plugin = require('./plugin')
var fastify = require('fastify')() fastify.register(plugin)

注意,插件是有作用域的:

fastify.register((instance, opts, next) => {
instance.decorate('util', (a, b) => a + b)
console.log(instance.util('that is ', ' awesome')) next()
}) fastify.register((instance, opts, next) => {
console.log(instance.util('that is ', ' awesome')) // 抛出异常 next()
})

在第二个 register 函数中 instance.util 会抛出异常,因为 util 只存在于第一个 register 函数的上下文中。

注意:封装只适用于祖先和兄弟作用域,不适用于子作用域。

fastify.register((instance, opts, next) => {
instance.decorate('util', (a, b) => a + b)
console.log(instance.util('that is ', ' awesome')) fastify.register((instance, opts, next) => {
console.log(instance.util('that is ', ' awesome')) // 不会抛出异常
next()
}) next()
}) fastify.register((instance, opts, next) => {
console.log(instance.util('that is ', ' awesome')) // 会抛出异常 next()
})

如果希望定义的方法在应用的任何地方都可以用,没有作用域的影响,则可以在根作用域中定义。或者使用 fastify-plugin 来包装插件。

使用 fastify-plugin 模块,可以传递一个表示 Fastify 的版本范围的参数作为插件将支持的 Fastify 版本。

const fp = require('fastify-plugin')

const plugin = fp(function (fastify, opts, next) {
fastify.decorate('utility', (a, b) => {
return a + b
})
next()
}, ">=0.30.2") fastify.register(plugin) fastify.register(function(fastify, opts, next){
console.log(fastify.utility(1, 3)) // 4
next()
})

在插件中使用路由钩子

只在某些特定的路由中执行路由钩子,可以这样做:

fastify.register((instance, opts, next) => {
instance.decorate('util', (req, key, value) => { req.key = value }) instance.addHook('preHandler', (req, reply, done) => {
instance.util(req, 'timestamp', new Date())
done()
}) instance.get('/plugin1', (req, reply) => {
reply.send(req)
}) next()
}) fastify.get('/plugin2', (req, reply) => {
reply.send(req)
})

/plugin2 将不会应用 preHandler 钩子。

常用插件

point-of-view 模板引擎

安装

npm install point-of-view --save

使用方法

fastify.register(require('point-of-view'), {
engine: {
ejs: require('ejs')
},
templates: './views' // 模板存放的目录
}) fastify.get('/', (req, reply) => {
reply.view('index.ejs', { text: 'text' })
})

fastify-cookie Cookie

安装

npm install fastify-cookie --save

使用方法

const fastify = require('fastify')()

fastify.register(require('fastify-cookie'), (err) => {
if (err) throw err
}) fastify.get('/', (req, reply) => {
const cookieFoo = req.cookies.foo // 得到发送过来的cookie中的foo字段 reply
.setCookie('foo', 'foo', { // 设置cookie
domain: 'example.com',
path: '/'
})
.send({hello: 'world'})
})

fastify-formbody 支持 application/x-www-form-urlencoded 内容类型

安装

npm install fastify-formbody --save

使用方式

const fastify = require('fastify')()

fastify.register(require('fastify-formbody'), {}, (err) => {
if (err) throw err
}) fastify.post('/', (req, reply) => {
reply.send(req.body)
}) fastify.listen(8000, (err) => {
if (err) throw err
})

更多插件可以访问https://www.fastify.io/ecosystem/

Fastify 系列教程到此结束。

Tips:访问 https://lavyun.gitbooks.io/fastify/content/ 查看我翻译的 Fastify 中文文档。

Fastify 系列教程四 (求对象、响应对象和插件)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. CRL快速开发框架系列教程四(删除数据)

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

  7. C#微信公众号开发系列教程四(接收普通消息)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  8. Android Studio系列教程四--Gradle基础

    Android Studio系列教程四--Gradle基础 2014 年 12 月 18 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang ...

  9. NGUI系列教程四(自定义Atlas,Font)

    今天我们来看一下怎么自定义NGUIAtlas,制作属于自己风格的UI.第一部分:自定义 Atlas1 . 首先我们要准备一些图标素材,也就是我们的UI素材,将其导入到unity工程中.2. 全选我们需 ...

随机推荐

  1. Excel表科学记数法的数字和文本的转换

    一,科学记数法的数字转换文本类型: 1,还未有数据,先选中列或者单元格 右键单击->设置单元格格式->文本->确定 2,已有数据,先选中列或者单元格 右键单击->设置单元格格式 ...

  2. python读取外部文件

    >>> pd.read_excel('c://111.xlsx') 年度排名 历史排名 电影名称 总票房 总人次 总场次 上映年份 操作 0 1 1 美人鱼 NaN -- -- 20 ...

  3. String和StringBuffer分别作为参数传递注意项

    public staticvoid main(){ String s1 = "abc"; StringBuffer sb = new StringBuffer(); sb.appe ...

  4. mysql操作sql的小技巧

    本篇集中整理一下执行sql的小技巧,这种方式不仅带来了操作上的便捷,也可以保证数据可以数据的安全性. 1:查询数据(保证查询性能) 首先想先解释一下 SELECT * 和 SELECT t.id , ...

  5. 【转】String字符串相加的问题

    String字符串相加的问题 前几天同事跟我说我之前写的代码中在操作字符串时候,使用字符串相加的方式而不是使用StringBuffer或者StringBuilder导致内存开销很大.这个问题一直在困扰 ...

  6. 关于select的一个错误---属性选择器

    错误: jquery 获取下拉框 text='1'的 option 的value 属性值  我写的var t= $("#selectID option[text='1']).val() ; ...

  7. android-蓝牙通信

    一:简介 由于项目曾经想用蓝牙通信,但由于蓝牙传输速度比较慢,最终还是没有使用蓝牙,不过还是在空闲之余研究了蓝牙通信,鉴于目前网上蓝牙这块教程并不多,尤其是从蓝牙扫描,蓝牙配对,蓝牙通信等完整的教程更 ...

  8. 用ESP8266+android,制作自己的WIFI小车(Android 软件)

    先说一下这篇文章里面的内容:TCP 客户端, 自定义对话框, 自定义按钮, ProgressBar竖直显示, 重力感应传感器,手机返回键新开启界面的问题(返回上次的界面),数据保存 软件的通信是配合 ...

  9. SAP 条形码

    使用系统生成的条形码 正常的排列;将扫描由左到右.旋转对齐将从上到下扫描90度倒立定线将扫描所180度从右到左底部对齐将从底部到顶部270度扫描 但在实际应用中,条形码的大小不仅与此处有关,也与字符格 ...

  10. 客户机中PLSQL DEV访问虚拟机中的ORCLE11g,错误百出!

    客户机中PLSQL DEV访问虚拟机中的ORCLE11g,错误百出! 创建时间: 2017/10/14 18:44 作者: CNSIMO 标签: ORACLE 忙了一下午,只有两个字形容:麻烦!   ...