Fastify 系列教程四 (求对象、响应对象和插件)
Fastify 系列教程:
- Fastify 系列教程一 (路由和日志)
- Fastify 系列教程二 (中间件、钩子函数和装饰器)
- Fastify 系列教程三 (验证、序列化和生命周期)
- 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 系列教程四 (求对象、响应对象和插件)的更多相关文章
- Fastify 系列教程一(路由和日志)
介绍 Fastify是一个高度专注于以最少开销和强大的插件架构,为开发人员提供最佳体验的Web框架. 它受到了 Hapi 和 Express 的启发,是目前最快的 Node 框架之一. Fastify ...
- Fastify 系列教程二 (中间件、钩子函数和装饰器)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) 中间件 Fastify 提供了与 Express 和 Restify ...
- Fastify 系列教程三 (验证、序列化和生命周期)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) 验证 Fast ...
- Fastify 系列教程二 (中间件、钩子函数和装饰器)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...
- Fastify 系列教程一 (路由和日志)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...
- CRL快速开发框架系列教程四(删除数据)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- C#微信公众号开发系列教程四(接收普通消息)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- Android Studio系列教程四--Gradle基础
Android Studio系列教程四--Gradle基础 2014 年 12 月 18 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang ...
- NGUI系列教程四(自定义Atlas,Font)
今天我们来看一下怎么自定义NGUIAtlas,制作属于自己风格的UI.第一部分:自定义 Atlas1 . 首先我们要准备一些图标素材,也就是我们的UI素材,将其导入到unity工程中.2. 全选我们需 ...
随机推荐
- 纳税服务系统【统计图Fusionchart】
需求 我们在投诉模块中还有一个功能没有实现: 统计:根据年度将相应年度的每个月的投诉数进行统计,并以图表的形式展示在页面中:在页面中可以选择查看当前年度及其前4年的投诉数.在页面中可以选择不同的年度, ...
- System.getProperty()参数大全
System.getProperty()获取Java各种配置属性,参数如下: Java.version Java 运行时环境版本 java.vendor Java 运行时环境供应商 java.vend ...
- 自己把jar包添加到maven仓库中
定制库到Maven本地资源库 这里有2个案例,需要手动发出Maven命令包括一个 jar 到 Maven 的本地资源库. 要使用的 jar 不存在于 Maven 的中心储存库中. 您创建了一个自定义的 ...
- MongoDB的备份和部署 高级功能索引,聚合复制,分片
创建备份 MongoDB 数据转储 为了在 MongoDB 中创建数据库备份,需要使用 mongodump 命令.该命令会将服务器上的所有数据都转储到 dump 目录中.你可以使用很多选项来限制转储的 ...
- css3新属性的学习使用
display 可选值:none隐藏元素: block显示为块级元素: inline显示为行级元素 inlineblock显示为内联块级元素,本身将是一个行级元素,但是拥有 块级元素的所有属性,比如宽 ...
- Java中迭代器Iterator的使用
Java集合类中Map接口下的相关类并没有像Collection接口的相关类一样实现get()方法,因此在要实现遍历输出的场景中没法直接用get()方法来取得对象中的数据,但Java本身提供了另一种遍 ...
- java 面向对象 2
一.JAVA类的定义 JAVA里面有class关键字定义一个类,后面加上自定义的类名即可.如这里定义的person类,使用class person定义了一个person类,然后在person这个类的类 ...
- MMORPG战斗系统随笔(二)、浅谈场寻路Flow Field PathFinding算法
转载请标明出处http://www.cnblogs.com/zblade/ 今天给大家带来一篇游戏中寻路算法的博客.去年,我加入一款RTS的游戏项目,负责开发其中的战斗系统,战斗系统的相关知识,属于游 ...
- OpenCV探索之路(二十五):制作简易的图像标注小工具
搞图像深度学习的童鞋一定碰过图像数据标注的东西,当我们训练网络时需要训练集数据,但在网上又没有找到自己想要的数据集,这时候就考虑自己制作自己的数据集了,这时就需要对图像进行标注.图像标注是件很枯燥又很 ...
- 糖果大战 hdu1204
糖果大战 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...