zoukankan      html  css  js  c++  java
  • 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' })
    })
    

    安装

    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 中文文档。

  • 相关阅读:
    js-监听网络状态
    call、apply、bind三者比较
    弹框滑动击穿问题
    Vue指令及自定义指令的使用
    vue-cli 运行打开浏览器
    递归判断多维数组中对象是否有值
    sync 修饰符在Vue中如何使用
    自定义组件 v-model 的使用
    Object.keys( )与 for in 区别
    mongodb 安装
  • 原文地址:https://www.cnblogs.com/smartXiang/p/7753721.html
Copyright © 2011-2022 走看看