在 Node.js Web 框架的序列中,Fastify 是一个相对年轻但定位十分明确的选择:它把性能和开发者体验同时作为第一优先级,通过 schema 驱动的序列化、高度优化的路由匹配和异步插件体系,在保持代码优雅的同时将吞吐量推向极致。这一节我们重点剖析 Fastify 的三大核心能力:高性能设计、JSON 序列化优化以及它的插件体系。
12.4.1 高性能设计:从路由到生命周期的最优路径
Fastify 在“快”这件事上从一开始就做了全链路的优化,而不是单纯靠剥离功能来提速。它的高性能主要体现在以下几个方面:
1. 高效的 Radix Tree 路由
Fastify 使用 find-my-way 作为底层的路由匹配引擎,这是一棵精心实现的基数树(Radix Tree)。对于形如 /user/:id/posts 这样的 URL,它会在 O(URL 长度) 的时间内完成匹配,而不需要遍历所有注册的路由。这意味着即使注册了上百条路由,请求分发也几乎没有任何额外开销。相比之下,Express 内部用的是正则数组线性匹配,路由过多时性能会逐步下降。
2. 极简的中间件模型与 Hook 系统
Fastify 没有像 Express 那样强依赖堆栈式的中间件,而是提供了更轻量的 生命周期钩子(Hooks)。例如 onRequest、preHandler、onSend、onResponse 等等,这些钩子允许开发者在请求处理的特定阶段插入逻辑,且全部支持 async/await。这种设计减少了中间件逐层调用的开销,同时保持了流程的清晰。
fastify.addHook('onRequest', async (request, reply) => {
// 验证请求头,可以 async
});
fastify.addHook('preHandler', async (request, reply) => {
// 权限校验
});
3. 内置的响应优化与极低的对象分配
Fastify 会尽可能重用对象和缓冲区,避免不必要的内存分配。例如,它内部的请求对象经过精简,不会像 Express 那样携带大量用不到的方法和属性,减少了 GC 压力。同时它原生支持压缩(gzip/brotli)、缓存控制以及 304 状态处理,无需额外中间件即可获得高性能的 HTTP 服务。
4. 近乎零开销的日志
Fastify 内置的日志模块基于 pino,它是 Node.js 生态中性能最高的日志库之一。日志记录本身不会因为字符串拼接或序列化而拖慢请求速度,通过惰性求值和结构化输出,在大多数场景下日志开销可忽略不计。
综合这些设计,Fastify 在标准 Web 请求场景下的吞吐量通常比 Express 高至 3-5 倍,甚至在一些基准测试中超过了 Koa,与纯原生 http 模块的差距也控制在很小的比例内。
12.4.2 JSON 序列化优化:让数据输出快成直线
在 RESTful API 服务中,JSON 序列化往往是消耗 CPU 最大的环节之一。传统的 JSON.stringify(obj) 需要动态遍历对象属性、处理类型转换,对于结构固定的接口响应,这其中有大量的重复判断工作。Fastify 通过 基于 JSON Schema 的静态序列化 彻底改变了这一状况。
核心原理:fast-json-stringify
Fastify 引入了一个专门优化的序列化库 fast-json-stringify。它的工作原理是:根据开发者定义的 JSON Schema,在启动阶段动态生成一个专用的序列化函数。这个函数由一连串手写的字符串拼接指令构成,避开了 JSON.stringify 的动态分析步骤,速度可以快上数倍。
一个示例会非常直观地说明这一点。假设我们有一个返回用户数据的接口:
const fastify = require('fastify')({ logger: false });
const userSchema = {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string' },
email: { type: 'string', format: 'email' },
active: { type: 'boolean' },
},
};
fastify.get('/user', {
schema: {
response: {
200: userSchema,
},
},
handler: async (request, reply) => {
const user = await getUserFromDB();
return user;
},
});
当我们这样定义了 response schema 后,Fastify 会在启动时自动生成一个高性能的序列化函数。这个函数大致等价于:
function myFastSerialize(obj) {
return '{"id":' + obj.id + ',"name":"' + obj.name + '","email":"' + obj.email + '","active":' + obj.active + '}';
}
它直接拼接字符串,并且可以在编译期检查字段是否存在、类型是否正确,省去了运行时遍历和类型判断。在真实负载下,这种优化的序列化速度可达到 JSON.stringify 的 2-5 倍,在高并发 JSON API 中带来的 CPU 节省非常可观。
Schema 驱动的验证与文档
Schema 的作用远不止序列化优化。Fastify 同时利用这些 Schema 自动完成以下工作:
- 输入验证:对请求的 headers、query、params、body 进行类型校验,不合规的请求直接返回 400 错误,无需手动编写校验代码。
- 自动生成 Swagger/OpenAPI 文档:只需引入
fastify-swagger插件,就能从路由 Schema 中生成标准的 API 文档,零额外维护成本。 - 类型一致性保证:结合 TypeScript,可以从 Schema 推断出请求和响应的类型,进一步减少出错可能。
这种 “定义一次 Schema,得到验证、序列化、文档三重收益” 的模式,非常契合严肃项目中对接口规范性与性能的双重要求。
12.4.3 插件体系:异步组合与可拔插的架构
Fastify 的插件系统基于 avvio 库构建,它的设计哲学是“一切皆插件”。无论是路由、数据库连接、认证模块,还是配置加载,都可以封装为可复用的插件。这个体系有三个突出特性:
1. 异步启动与依赖管理
在 Express 或 Koa 中,中间件的注册通常是同步顺序执行的,这让一些需要异步初始化的依赖(如连接数据库、加载配置)变得困难,常常需要额外的启动脚本。Fastify 的插件注册方法 fastify.register(plugin, opts) 支持 async/await,允许插件完成异步初始化后再暴露功能:
fastify.register(async function (instance, opts) {
const db = await connectDatabase(opts.dbURL);
// 将 db 装饰到实例上
instance.decorate('db', db);
});
这种机制确保了依赖就绪后才开始接受请求,避免“服务已启动但数据库未连接”的尴尬。avvio 还会自动分析插件的依赖顺序,按照合理的先后加载。
2. 作用域隔离与装饰器模式
每个插件都会获得一个隔离的 Fastify 实例(通过 instance 参数),可以在该实例上注册新的路由、装饰新方法,而不会污染全局。例如,一个处理订单业务的插件可以拥有自己的 /orders 路由分组和内部中间件,与其他插件互不干扰。同时,通过 decorate、decorateRequest、decorateReply 等方法,插件可以向请求上下文注入共享工具,如 request.user、reply.render 等,实现优雅的依赖注入。
3. 丰富的官方与社区插件
Fastify 团队维护了一系列高质量的插件,涵盖了实际项目中大部分需求:
fastify-env:加载环境变量并校验。fastify-cors、fastify-helmet:安全相关头处理。fastify-rate-limit:接口限流。fastify-websocket:原生 WebSocket 支持。fastify-compress:响应压缩。fastify-jwt、fastify-cookie:认证与会话。
这些插件都遵循同样的 register 模式,配置风格一致,极大降低了学习成本和集成摩擦。
12.4.4 Fastify 的定位与选型建议
Fastify 并不是要取代 Express 或 Koa,而是为那些对响应速度有更高要求、需要严格接口规范的项目提供了一个现代化选项。如果你正在开发一个高并发的 REST API、微服务网关、或者对接口文档自动化有强需求的 BFF 层,Fastify 会是比 Express 更优的选择。
它的主要代价在于 Schema 的定义需要额外的学习与维护,对于简单的静态页面服务或原型验证可能显得过于“正式”。但当项目规模扩大、性能瓶颈开始显现时,Fastify 的 schema 驱动和优化体系能够持续提供益处,而不会像 Express 那样需要大量手工优化。
总而言之,Fastify 用一套精心设计的组合拳——高效路由、schema 序列化、异步插件——重新定义了 Node.js Web 框架的性能上限,同时保持了出色的开发体验。它是框架选型时不能忽视的重要一极。