Fastify 系列教程一 (路由和日志)
2017-10-25 14:15
344 查看
Fastify 系列教程:
Fastify 系列教程一 (路由和日志)
Fastify 系列教程二 (中间件、钩子函数和装饰器)
Fastify 系列教程三 (验证、序列化和生命周期)
Fastify 系列教程四 (请求对象、响应对象和插件)
它受到了 Hapi 和 Express 的启发,是目前最快的 Node 框架之一。
Fastify 独特的将 JSON Schema 应用到请求时的 validation 和响应时的 serialization,作者写的
在命令行输入 node app.js 启动服务,在浏览器访问 localhost:3030 就可以访问到了:
上述代码将匹配到访问 '/home' 的 post 请求。
详细的 option 配置如下:
此时使用
注意:Fastify 只支持
所支持的 url 格式可以查看:https://github.com/delvedor/find-my-way#supported-path-formats
需要符合 JSON Schema 的格式。
使用 schema 是 Fastify 比其他框架都快的原因所在,如何理解这个 schema 呢?大家都知道,在 JSON 里面有
好了,言归正传,使用 schema 示例:
当访问 http://localhost:3030/put_and_post?name=2 时可以正常得到
如果访问 http://localhost:3030/put_and_post?name=true 会发生什么呢?对不起,Fastify 会返回
如果将
客户端将不会得到
比如使用 Joi:
fastify 支持类似
示例:
可以看到,我们没有调用
警告:如果同时使用
Fastify 提供了快速而智能的方式来创建不同版本的相同的api,而无需手动更改所有路由名称:
因为在编译时会自动处理前缀(这也意味着性能不会受到影响),所以Fastify不会抱怨两个不同的路由使用相同的名称。
现在客户端将可以访问以下路由:
此时,当收到请求后,会在控制台打印日志:
Fastify 的更多使用将在接下来的博客中说明。
Tips:
访问 https://lavyun.gitbooks.io/fastify/content/ 查看我翻译的 Fastify 中文文档。
访问我的个人博客查看我的最新动态 lavyun.cn
Fastify 系列教程一 (路由和日志)
Fastify 系列教程二 (中间件、钩子函数和装饰器)
Fastify 系列教程三 (验证、序列化和生命周期)
Fastify 系列教程四 (请求对象、响应对象和插件)
介绍
Fastify是一个高度专注于以最少开销和强大的插件架构,为开发人员提供最佳体验的Web框架。它受到了 Hapi 和 Express 的启发,是目前最快的 Node 框架之一。
Fastify 独特的将 JSON Schema 应用到请求时的 validation 和响应时的 serialization,作者写的
fast-json-stringify包更是达到了 2x faster than JSON.stringify() 的神奇效果。
起步
安装
输入如下指令安装 fastify :npm i fastify --save
第一个 fastify 应用
app.js:const fastify = require('fastify')() // 注册匹配到 '/' 的路由 fastify.get('/', function (request, reply) { reply .send({ text: 'hello fastify' }) }) // 监听 3030 端口 fastify.listen(3030, err => { if (err) { console.log(err) } })
在命令行输入 node app.js 启动服务,在浏览器访问 localhost:3030 就可以访问到了:
路由
使用fastify.route(option)注册一个路由:
fastify.route({ method: 'post', url: '/home', handler: function(request, reply){ reply.send({text: 'hello fastify'}) } })
上述代码将匹配到访问 '/home' 的 post 请求。
详细的 option 配置如下:
method:
目前只支持'DELETE',
'GET',
'HEAD',
'PATCH',
'POST',
'PUT'和
'OPTIONS'。也可以是一个数组:
fastify.route({ method: ['POST', 'PUT'], url: '/put_and_post', handler: function(request, reply){ reply.send({hello: 'world'}) } })
此时使用
POST或者
PUT方式访问
/put_and_post都能成功响应。
注意:Fastify 只支持
application/json内容类型,如果想解析其他类型可以查看社区插件,fastify-formbody 可以解析
x-www-form-urlencoded请求类型,使用 fastify-multipart 处理
form-data类型请求。或者使用 ContentTypeParser 方法自定义内容类型解析器。
url:
路由匹配的路径,也可以使用path代替。
所支持的 url 格式可以查看:https://github.com/delvedor/find-my-way#supported-path-formats
schema:
一个包含请求和响应模式的对象。需要符合 JSON Schema 的格式。
body: 验证请求体, 必须是
'POST'或者
'PUT'请求。
querystring: 验证查询字符串。可以是一个完成的 JSON Schema 对象(符合
{type: "object", properties: {...}})或者没有
type和
properties属性,而只有查询字符串列表。
params: 验证
params
response: 过滤并生成响应的 schema ,可以提升 10-20% 的吞吐量。
headers: 验证请求头。
使用 schema 是 Fastify 比其他框架都快的原因所在,如何理解这个 schema 呢?大家都知道,在 JSON 里面有
string,
number,
object,
array,
null共五中类型,不同的类型格式是不一样的,比如字符串两头需要加引号,数组两头需要加括号等等,如果不用 schema 指明 json 是何种模式的话,原生的
JSON.stringify()会先判断字段的类型后再做相应字符串化方法。而 JSON Schema 就是来定义 json 的数据格式的,通过 JSON Schema 可以达到验证 JSON 是否符合规定的格式。而框架作者独创的使用 JSON Schema 并手写
stringify(fast-json-stringify) ,达到了 2x faster than JSON.stringify() ,也是令人敬佩不已,也是正如 贺师俊 老师评论的那样:
好了,言归正传,使用 schema 示例:
fastify.route({ method: 'GET', url: '/', schema: { querystring: { name: { type: 'number' } }, response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }, handler: function (request, reply) { console.log(request.query) reply.send({ hello: 'world' }) } })
当访问 http://localhost:3030/put_and_post?name=2 时可以正常得到
{"hello": "world"},同时控制台也会输入
{name: 2},注意,
name=2这条查询字符串也被自动转成了
number类型了。
如果访问 http://localhost:3030/put_and_post?name=true 会发生什么呢?对不起,Fastify 会返回
400错误,因为
true不是
number类型,而是一个字符串:
{ "error": "Bad Request", "message": [{ "keyword":"type", "dataPath":".name", "schemaPath":"#/properties/name/type", "params":{"type":"number"}, "message":"should be number" }], "statusCode": 400 }
如果将
reply.send({hello: 'world'}),改成
reply.send({text: 'world'})会发生什么呢?
客户端将不会得到
text这个字段,因为
{text: 'world'}不符合定义的
responese规则,最终只会得到
{}。
beforeHandler(request, reply, done):
在处理请求之前调用的函数,可以在这里处理用户认证:fastify.route({ method: 'POST', path: '/authentication', beforeHandler: function(request, reply, done){ if(request.body.username === 'lavyun') { done() } else { reply.send({ meg: 'Authentication failed!', code: '1' }) } }, handler: function(request, reply){ reply.send({ code: '0', msg: 'Authentication success!' }) } })
handler(request, reply):
用来处理请求的函数。schemaCompiler(schema):
schemaCompiler是一个指定 schema 编译器的方法。(用来验证 body, params, headers, querystring)。默认的
schemaCompiler返回一个实现
ajv接口的编译器。
比如使用 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) })
fastify 支持类似 Express/Restify
的路由语法:
fastify.get(path, [options], handler)
fastify.head(path, [options], handler)
fastify.post(path, [options], handler)
fastify.put(path, [options], handler)
fastify.delete(path, [options], handler)
fastify.options(path, [options], handler)
fastify.patch(path, [options], handler)
fastify.all(path, [options], handler)
示例:
const opts = { schema: { response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } } } fastify.get('/', opts, (req, reply) => { reply.send({ hello: 'world' }) })
Async Await
使用async/await:
fastify.get('/', options, async function (request, reply) { var data = await getData() var processed = await processData(data) return processed })
可以看到,我们没有调用
reply.send来返回数据给用户,而是使用
return,当然你也可以使用
replay.send:
fastify.get('/', options, async function (request, reply) { var data = await getData() var processed = await processData(data) reply.send(processed) })
警告:如果同时使用
return和
reply.send,则后者将会被舍弃。
路由前缀
有时我们会维护两套不同版本的api,一般我们都会手动的给所有的路由加上版本号前缀,例如:v1/user。
Fastify 提供了快速而智能的方式来创建不同版本的相同的api,而无需手动更改所有路由名称:
// server.js const fastify = require('fastify')() fastify.register(require('./routes/v1/users'), { prefix: '/v1' }) fastify.register(require('./routes/v2/users'), { prefix: '/v2' }) fastify.listen(3000)
// routes/v1/users.js module.exports = function (fastify, opts, next) { fastify.get('/user', handler_v1) next() }
// routes/v2/users.js module.exports = function (fastify, opts, next) { fastify.get('/user', handler_v2) next() }
因为在编译时会自动处理前缀(这也意味着性能不会受到影响),所以Fastify不会抱怨两个不同的路由使用相同的名称。
现在客户端将可以访问以下路由:
/v1/user
/v2/user
日志
日志功能默认是关闭的,如果需要启用,可以这样做:const fastify = require('fastify')({ logger: true }) fastify.get('/', function (req, reply) { reply.send({ hello: 'world' }) }) // 监听 3030 端口 fastify.listen(3030, err => { if (err) { console.log(err) } })
此时,当收到请求后,会在控制台打印日志:
{ "pid":78817, "hostname":"localhost", "level":30, "time":1508910898897, "msg":"incoming request", "reqId":1, "req":{ "id":1, "method":"GET", "url":"/", "remoteAddress":"::1", "remotePort":57731 }, "v":1 } { "pid":78817, "hostname":"localhost", "level":30, "time":1508910898907, "msg":"request completed", "reqId":1, "res":{ "statusCode":200 }, "responseTime":8.21057403087616, "v":1 }
Fastify 的更多使用将在接下来的博客中说明。
Tips:
访问 https://lavyun.gitbooks.io/fastify/content/ 查看我翻译的 Fastify 中文文档。
访问我的个人博客查看我的最新动态 lavyun.cn
相关文章推荐
- 【Web API系列教程】2.3 — ASP.NET Web API 2中的属性路由
- SCCM 2007系列教程之三日志文件
- CYQ.Data V5 从入门到放弃ORM系列:教程 - Log、SysLogs两个日志类使用
- php mvc开发系列教程第二节 单一入口文件(路由文件)
- Spring Boot系列教程六:日志输出配置log4j2
- Java日志服务入门系列教程——(2)Apache log4j入门
- ASP.NET MVC3 系列教程 - URL友好化的重型武器[路由]
- CYQ.Data V5 从入门到放弃ORM系列:教程 - Log、SysLogs两个日志类使用
- Java日志服务入门系列教程——(1)SLF4J入门
- 解读ASP.NET 5 & MVC6系列教程(9):日志框架
- ASP.NET MVC3 系列教程 - URL友好化的重型武器[路由]
- nodejs+mongodb系列教程之(3/5)--理解路由和中间件
- angular2系列教程(十一)路由嵌套、路由生命周期、matrix URL notation
- Java日志服务入门系列教程——(2)Apache log4j入门
- [Gradle中文教程系列]-跟我学Gradle-附录-2.Gradle的日志级别
- Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数
- RabbitMQ系列教程之四:路由(Routing)(转载)
- Java日志服务入门系列教程——(1)SLF4J入门
- Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数
- RabbitMQ系列教程之四:路由(Routing)