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

本文介绍了Fastify框架中的验证与序列化功能,包括如何利用JSONSchema进行请求验证,以及使用fast-json-stringify进行高效序列化。此外,还详细讲解了Fastify的生命周期。

Fastify 系列教程:

验证

Fastify 可以验证请求信息,只有符合验证规则的请求才会被处理。

JSON Schema

什么是 JSON Schema ,通俗来讲,JSON Schema 就是“描述 JSON 数据格式的一段 JSON”。

首先,JSON Schema 也是一个 JSON 字符串,下面来看一个简单的 JSON Schema:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Product",
    "description": "A product from Acme's catalog",
    "type": "object",
    "properties": {
        "id": {
            "description": "The unique identifier for a product",
            "type": "integer"
        },
        "name": {
            "description": "Name of the product",
            "type": "string"
        },
        "price": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true
        }
    },
    "required": ["id", "name", "price"]
}

上面这段规则描述了这样一个JSON:

1、type 表示该 JSON 的类型是一个 "object"。

type 的参数可以是:number, integer(整型), string, boolean, array, object 或者 null。也可以是一个包含上述类型的数组。

  1. schema: { "type": "number" }

    valid: 1, 1.5

    invalid: "abc", "1", [], {}, null, true

  2. schema: { "type": "integer" }

    valid: 1, 2

    invalid: "abc", "1", 1.5, [], {}, null, true

  3. schema: { "type": ["number", "string"] }

    valid: 1, 1.5, "abc", "1"

    invalid: [], {}, null, true

2、properties 定义了 JSON 的字段规则。

3、requirede 定义了必须存在的属性列表。

我们来看一下可以用于这一模式中的各种重要关键字:

关键词描述
$schema$schema 关键字状态,表示这个模式与 v4 规范草案书写一致。
title用它给我们的模式提供了标题。
description关于模式的描述。
typetype 关键字在我们的 JSON 数据上定义了第一个约束:必须是一个 JSON 对象。
properties定义各种键和他们的值类型,以及用于 JSON 文件中的最小值和最大值。
required存放必要属性列表。
minimum给值设置的约束条件,表示可以接受的最小值。
exclusiveMinimum如果存在 "exclusiveMinimum" 并且具有布尔值 true,如果它严格意义上大于 "minimum" 的值则实例有效。
maximum给值设置的约束条件,表示可以接受的最大值。
exclusiveMaximum如果存在 "exclusiveMinimum" 并且具有布尔值 true,如果它严格意义上小于 "maximum" 的值则实例有效。
multipleOf如果通过这个关键字的值分割实例的结果是一个数字则表示紧靠 "multipleOf" 的数字实例是有效的。
maxLength字符串实例字符的最大长度数值。
minLength字符串实例字符的最小长度数值。
pattern如果正则表达式匹配实例成功则字符串实例被认为是有效的。

通过上面的配置,我们就可以验证某个 JSON 是否符合要求了:

validate(JSONSchema, myJson)

有同学肯定会问,这个验证函数 validate 从哪来?github 上有各种第三方验证器:

语言程序库
CWJElement (LGPLv3)
Javajson-schema-validator (LGPLv3)
.NETJson.NET (MIT)
ActionScript 3Frigga (MIT)
Haskellaeson-schema (MIT)
PythonJsonschema
Rubyautoparse (ASL 2.0); ruby-jsonschema (MIT)
PHPphp-json-schema (MIT). json-schema (Berkeley)
JavaScriptOrderly (BSD); JSV; json-schema; Matic (MIT); Dojo; Persevere (modified BSD or AFL 2.0); schema.js.

而 Fastify 所使用的 ajv 也是一个 JSON Schema 验证器,号称:

The fastest JSON Schema validator for Node.js and browser with draft 6 support.

有了上面的介绍,我们就来看一下 Fastify 是怎么验证请求信息的吧:

非常简单,只需要添加需要验证的字段即可。

  • body:验证请求体,必须是 POST 或者 PUT 请求。
  • querystring: 验证查询字符串。可以是一个完成的 JSON Schema 对象(符合 {type: "object", properties: {...}} 的格式)或者没有 typeproperties 属性,而只有查询字符串列表。(查看下面的例子)
  • params: 验证路由参数。
  • headers: 验证请求头。

示例:

fastify.post('/add', {
  schema: {
    body: {
      type: 'object',
      properties: {
        name: {
          type: 'string'
        },
        id: {
          type: 'number'
        }
      },
      required: ['name', 'id']
    }
  }
}, function(request, reply){
  reply.send('validate successful')
})

当发送一个body为

{
  "name": "lavyun",
  "id": "hello"
}

post 请求时,会得到错误:

{
    "error": "Bad Request",
    "message": "[{\"keyword\":\"type\",\"dataPath\":\".id\",\"schemaPath\":\"#/properties/id/type\",\"params\":{\"type\":\"number\"},\"message\":\"should be number\"}]",
    "statusCode": 400
}

因为 id 不符合 number 类型,把 id 改成 1 就可以了。

注意:Fastify 配置了 avj 默认会自动把不符合类型的值强制转换成规则中定义的类型,如果仍然不符合类型,则返回错误:

例如

{
  "name": null,
  "id": "2"
}

也会验证通过,因为被强转成:

  "name": "null",
  "id": 2

如果不想被强制转换,可以通过配置 avj 关闭该功能:

const fastify = require('fastify')({
  ajv: {
    coerceTypes: false
  }
})

Schema Compiler

schemaCompiler 是一个指定 schema 编译器的方法。(用来验证 body, params, headers, querystring)。默认的 schemaCompiler 返回一个实现 ajv 接口的编译器。

如果你想更改默认的 ajv 实例,可以传入 ajv 配置项, 查看 Ajv documentation 了解更多。

或许想直接更换验证的库,比如使用 Joi:

const Joi = require('joi')

fastify.post('/the/url', {
  schema: {
    body: Joi.object().keys({
      hello: Joi.string().required()
    }).required()
  },
  schemaCompiler: schema => data => Joi.validate(data, schema)
})

序列化

通常,我们会通过 JSON 将数据发送给客户端, Fastify 提供了一个强大的工具: fast-json-stringify,这是一个比原生 JSON.stringify() 还快的 JSON 格式化器,其原理就是通过配合 JSON Schema,快速定位字段的类型,省去了原生 JSON.stringify() 内部判断字段类型的步骤,实现了 two times faster than JSON.stringify(). 的效果。

在路由选项中传入了 output schema,fastify 就会使用它。

const schema = {
  response: {
    200: {
      type: 'object',
      properties: {
        value: { type: 'string' },
        otherValue: { type: 'boolean' }
      }
    }
  }
}

response schema 是基于状态码的,如果想应用相同的 schema 给多个同级状态码, 可以使用 2xx

const schema = {
  response: {
    '2xx': {
      type: 'object',
      properties: {
        value: { type: 'string' },
        otherValue: { type: 'boolean' }
      }
    },
    201: {
      type: 'object',
      properties: {
        value: { type: 'string' }
      }
    }
  }
}

patternProperties

fast-json-stringify 支持属性匹配,符合属性正则的字段都会被验证:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    nickname: {
      type: 'string'
    }
  },
  patternProperties: {
    'num': {
      type: 'number'
    },
    '.*foo$': {
      type: 'string'
    }
  }
})
 
const obj = {
  nickname: 'nick',
  matchfoo: 42,
  otherfoo: 'str'
  matchnum: 3
}
 
console.log(stringify(obj)) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"nickname":"nick"}'

更多 fast-json-stringify 的使用可以查看文档

生命周期

Fastify 严格遵循内部生命周期的架构。在每个部分的右侧分支上都有生命周期的下一个阶段,左侧的分支上有相应的错误状态码,如果父代引发错误,则会生成相应的错误状态码(注意,所有错误都由Fastify自动处理)。

Fastify 生命周期图示:

Incoming Request (请求到达)
  │
  └─▶ Instance Logger (实例化 Logger)
        │
        └─▶ Routing (路由匹配)
             │
       404 ◀─┴─▶ onRequest Hook (onRequest钩子)
                  │
        4**/5** ◀─┴─▶ run Middlewares (执行中间件)
                        │
              4**/5** ◀─┴─▶ Parsing (解析请求对象)
                             │
                       415 ◀─┴─▶ Validation (验证)
                                   │
                             400 ◀─┴─▶ preHandler Hook (preHandler钩子)
                                         │
                               4**/5** ◀─┴─▶ beforeHandler
                                               │
                                     4**/5** ◀─┴─▶ User Handler
                                                     │
                                                     └─▶ Reply (响应)
                                                          │ │
                                                          │ └─▶ Outgoing Response (发出响应)
                                                          │
                                                          └─▶ onResponse Hook (onResponese钩子

Fastify 的更多使用将在接下来的博客中说明。

参考文档:
JSON 模式 / http://wiki.jikexueyuan.com/project/json/schema.html

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

访问lavyun.cn 查看我的个人博客

转载于:https://www.cnblogs.com/smartXiang/p/7749737.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值