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 关于模式的描述。
type type 关键字在我们的 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 上有各种第三方验证器:

语言 程序库
C WJElement (LGPLv3)
Java json-schema-validator (LGPLv3)
.NET Json.NET (MIT)
ActionScript 3 Frigga (MIT)
Haskell aeson-schema (MIT)
Python Jsonschema
Ruby autoparse (ASL 2.0); ruby-jsonschema (MIT)
PHP php-json-schema (MIT). json-schema (Berkeley)
JavaScript Orderly (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 查看我的个人博客

Fastify 系列教程三 (验证、序列化和生命周期)的更多相关文章

  1. Vue.js 系列教程 3:Vue-cli,生命周期钩子

    原文:intro-to-vue-3-vue-cli-lifecycle-hooks 译者:nzbin 这是 JavaScript 框架 Vue.js 五篇教程的第三部分.在这一部分,我们将学习 Vue ...

  2. Maven使用教程三:maven的生命周期及插件机制详解

    前言 今天这个算是学习Maven的一个收尾文章,里面内容不局限于标题中提到的,后面还加上了公司实际使用的根据profile配置项目环境以及公司现在用的archetype 模板等例子. 后面还会总结一个 ...

  3. Windows 8 动手实验系列教程 实验5:进程生命周期管理

    动手实验 实验5:进程生命周期管理 2012年9月 简介 进程生命周期管理对构建Windows应用商店应用的开发者来说是需要理解的最重要的概念之一.不同于传统的Windows应用(它们即使在后台仍然继 ...

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

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

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

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

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

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

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

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

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

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

  9. 黄聪:Microsoft Enterprise Library 5.0 系列教程(三) Validation Application Block (高级)

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(三) Validation Application Block (高级) 企业库验证应用程序模块之配置文件模式: ...

随机推荐

  1. Vue-cli创建项目从单页面到多页面

    vue-cli创建项目从单页面到多页面 对于某些项目来说,单页面不能很好的满足需求,所以需要将vue-cli创建的单页面项目改为多页面项目. 需要修改以下几个文件: 1.下载依赖glob $npm i ...

  2. 25个最基本的JavaScript面试问题及答案

    1.使用 typeof bar === "object" 来确定 bar 是否是对象的潜在陷阱是什么?如何避免这个陷阱? 尽管 typeof bar === "objec ...

  3. SSH框架搭建最终版【测试、log4j、baseDao】

    最详细搭建SSH框架环境 本博文主要是讲解如何搭建一个比较规范的SSH开发环境,以及对它测试[在前面的搭建中,只是整合了SSH框架,能够使用SSH实现功能],而这次是相对规范的. 导入开发包 在Str ...

  4. Javascript-正则表达式-开发中的使用.

    -- "(-1~99)之间 -1表示无限次!" pattern="^((-1)|([0-9]{0,2}))$" -- "(0~99.99)之间 的金额 ...

  5. JDBC操作数据库之删除数据

    删除数据使用的SQL语句为delete语句,如果删除图书id为1的图书信息,其SQL语句为: delete from book where id=1 在实际开发中删除数据通常使用PreparedSta ...

  6. bind9的一些配置

    /etc/bind/named.conf.options:options { listen-on port 53 { any; }; // 监听在主机的53端口上.any代表监听所有的主机 direc ...

  7. GCD之并行串行区别

    1.用户自定义线程队列,创建时很容易创建 注意创建时的第一个参数:标记值,方便调试查看 1 2 dispatch_queue_t serialqueue=dispatch_queue_create(& ...

  8. Maven在Windows中的配置以及IDE中的项目创建

    Maven在Windows下的配置 1.Maven下载地址:http://maven.apache.org/download.cgi,下载红框里的版本即可. 2.解压到D盘: 3.修改配置文件sett ...

  9. Quartz源码——Quartz调度器的Misfire处理规则(四)

    Quartz调度器的Misfire处理规则 调度器的启动和恢复中使用的misfire机制,还需细化! SimpleTrigger的misfire机制 默认的 Trigger.MISFIRE_INSTR ...

  10. PHP 生成毫秒时间戳

    PHP的time()函数生成当前时间的秒数,但是在一些情况下我们需要获取当前服务器时间和GMT(格林威治时间)1970年1月0时0分0秒的毫秒数,与Java中的currentTimeMilis()函数 ...