Fastify 系列教程三 (验证、序列化和生命周期)
Fastify 系列教程:
- Fastify 系列教程一 (路由和日志)
- Fastify 系列教程二 (中间件、钩子函数和装饰器)
- 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。也可以是一个包含上述类型的数组。
schema:
{ "type": "number" }valid:
1,1.5invalid:
"abc","1",[],{},null,trueschema:
{ "type": "integer" }valid:
1,2invalid:
"abc","1",1.5,[],{},null,trueschema:
{ "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: {...}}的格式)或者没有type和properties属性,而只有查询字符串列表。(查看下面的例子)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 系列教程三 (验证、序列化和生命周期)的更多相关文章
- Vue.js 系列教程 3:Vue-cli,生命周期钩子
原文:intro-to-vue-3-vue-cli-lifecycle-hooks 译者:nzbin 这是 JavaScript 框架 Vue.js 五篇教程的第三部分.在这一部分,我们将学习 Vue ...
- Maven使用教程三:maven的生命周期及插件机制详解
前言 今天这个算是学习Maven的一个收尾文章,里面内容不局限于标题中提到的,后面还加上了公司实际使用的根据profile配置项目环境以及公司现在用的archetype 模板等例子. 后面还会总结一个 ...
- Windows 8 动手实验系列教程 实验5:进程生命周期管理
动手实验 实验5:进程生命周期管理 2012年9月 简介 进程生命周期管理对构建Windows应用商店应用的开发者来说是需要理解的最重要的概念之一.不同于传统的Windows应用(它们即使在后台仍然继 ...
- Fastify 系列教程一(路由和日志)
介绍 Fastify是一个高度专注于以最少开销和强大的插件架构,为开发人员提供最佳体验的Web框架. 它受到了 Hapi 和 Express 的启发,是目前最快的 Node 框架之一. Fastify ...
- Fastify 系列教程二 (中间件、钩子函数和装饰器)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) 中间件 Fastify 提供了与 Express 和 Restify ...
- Fastify 系列教程四 (求对象、响应对象和插件)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...
- Fastify 系列教程二 (中间件、钩子函数和装饰器)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...
- Fastify 系列教程一 (路由和日志)
Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...
- 黄聪:Microsoft Enterprise Library 5.0 系列教程(三) Validation Application Block (高级)
原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(三) Validation Application Block (高级) 企业库验证应用程序模块之配置文件模式: ...
随机推荐
- Python 的笔试题
其实大多数说学习Python 是纯兴趣,真的我不信,许多人已经工作了,没有那么多时间搞自己的纯兴趣了,都会为了生活奋斗,可以说转行来学python 就是未来加薪,当然,小编现在也快要准备工作了,所以也 ...
- 创建maven项目pom.xml第一行报错
之前也创建过几次maven项目,也是第一行报错,之前直接是右键项目强制更新maven好像就解决了,这次遇见这个问题使用这个方法好像不起作用了,给的一堆英文报错又看不懂,幸好在网上看见路人甲大神提示,根 ...
- Python学习笔记012_网络_异常
1,Python如何访问互联网? url + lib = urllib >>> # 使用urllib包下的request模块 >>> >>> i ...
- 庞玉栋:浅谈seo优化对于网站建设的重要性
根据最近做SEO优化经验而写 写的也都是我的方法 大神勿喷 SEO:英文Search Engine Optimization缩写而来, 中文意译为搜索引擎优化 如果你连个网站都没有那就点这里:如何拥 ...
- Java定时任务调度详解
前言 在实际项目开发中,除了Web应用.SOA服务外,还有一类不可缺少的,那就是定时任务调度.定时任务的场景可以说非常广泛,比如某些视频网站,购买会员后,每天会给会员送成长值,每月会给会员送一些电影券 ...
- 这是一名Java学者关于学习方向的建议
无可厚非,编程是一门艺术.但是辉煌的背后必须是一段辛苦的奋斗过程,而过程的引导方向就是最重要的一环.Java语言可谓是引领了编程的潮流,你会是怎样去学的呢? 这是一名Java学者的学习方向的建议 注: ...
- 初识Hibernate之环境搭建
相信所有做后端的程序员同行们,没有不知道Hibernate大名的.这是一个经典的轻量级Java EE持久层的解决方案,它使得我们程序员能以面向对象的思维操作传统的关系型数据库,这也是其存在的 ...
- oss滤网图片音视频过滤(1)内容检测
图片音视频过滤有好多方法,我这里就不一一介绍了,这篇文章只是简单介绍一下我在项目中使用阿里云oss滤网过滤的步骤 1.所遇问题: 1.图片视频鉴别时要设置textScanRequest.setUriP ...
- Vue.js的从入门到放弃进击录(一)
感谢我们项目组给机会,让我学了Vue.js,打开新世界大门...哈哈哈,也没有那么夸张,不过学下来确实觉得入门还是蛮容易的.我大概前前后后学了有一个月的样子,一开始只是比较急着可以写东西出来,后来因为 ...
- Hadoop安全(2)——————UserGroupInformation
UserGroupInformation保存hadoop用户及组信息 此类包装JAAS Subject,并提供确定用户的用户名和组的方法.它支持Windows,Unix和Kerberos登录模块.