目录
- 前言
- [一、Fastify 概览](#一、Fastify 概览)
- 二、入门快速示例(最小可运行)
- 三、核心概念详解
-
- [1、请求/响应 API](#1、请求/响应 API)
- [2、Schema(JSON Schema)](#2、Schema(JSON Schema))
- 3、Hooks(生命周期钩子)
- 4、Decorators(扩展实例/请求/回复)
- 5、Encapsulation(封装)
- 四、插件系统(最重要的机制)
- [五、性能相关(为什么 Fastify 快?如何优化)](#五、性能相关(为什么 Fastify 快?如何优化))
- [六、TypeScript 与 Fastify(企业级要点)](#六、TypeScript 与 Fastify(企业级要点))
-
- [1、基本 TypeScript 快速示例](#1、基本 TypeScript 快速示例)
- 2、类型扩展(decorate、plugin)
- 3、推荐工具链
- 七、路由与分层架构(最佳实践)
- 八、安全(必做项)
- 九、错误处理与日志
- 十、测试(单元、集成、端到端)
- 十一、常用与推荐插件(企业级清单)
- [十二、Express 到 Fastify 的迁移实务(要点)](#十二、Express 到 Fastify 的迁移实务(要点))
- 十三、部署与扩容(生产实践)
- [十四、监控指标 & 健康检查(建议)](#十四、监控指标 & 健康检查(建议))
- 十五、常见问题与排查指南
- [十六、性能调优 checklist(落地)](#十六、性能调优 checklist(落地))
- [十七、实战示例:一个带 Auth、DB、Swagger 的项目骨架(关键代码片段)](#十七、实战示例:一个带 Auth、DB、Swagger 的项目骨架(关键代码片段))
- [十八、Fastify 与其他框架对比(简要)](#十八、Fastify 与其他框架对比(简要))
前言
一、Fastify 概览
定义:Fastify 是一个以 性能 与 开发者体验 为目标的 Node.js web 框架。
核心特点:
- 高性能(序列化优化)
- 插件/封装机制
- 内置 schema 驱动校验与序列化
- 优秀的 TypeScript 支持
适用场景:
- 高并发 API 服务
- 微服务
- BFF
- Serverless
设计原则:
- 低开销的请求/响应序列化:使用 fast-json-stringify 优化 JSON 序列化。
- schema-first:用 JSON Schema 描述请求/响应,自动校验和序列化,性能更好。
- 插件封装(encapsulation):通过插件隔离作用域、依赖注入、避免全局污染。
- 尽量少做魔法:明确生命周期 hook,便于调试。
- 插件生态:大量插件(认证、Swagger、Redis、db 客户端等)。
二、入门快速示例(最小可运行)
cpp
// index.js
const fastify = require('fastify')({ logger: true });
fastify.get('/', async (request, reply) => {
return { hello: 'world' };
});
const start = async () => {
try {
await fastify.listen({ port: 3000 });
console.log('Server listening on 3000');
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
运行:
bash
node index.js
三、核心概念详解
1、请求/响应 API
- fastify.get/post/put/delete(path, opts, handler):支持返回 Promise 或直接 reply.send()。
- request:包含 params, query, body, headers, raw(原生 req)。
- reply:封装了 res,有 reply.code(201).send(obj), reply.header('x', 'y') 等。
示例:
cpp
fastify.post('/user/:id', async (request, reply) => {
const { id } = request.params;
const body = request.body;
reply.code(201).send({ id, ...body });
});
2、Schema(JSON Schema)
- 在 opts.schema 中定义 querystring, params, body, headers, response。
- Fastify 在接收请求时会校验(基于 AJV),在返回时会序列化/校验响应。
- schema 带来性能优化(编译一次后复用)。
示例:
cpp
fastify.route({
method: 'POST',
url: '/user',
schema: {
body: { type: 'object', required: ['name'], properties: { name: { type: 'string' } } },
response: { 201: { type: 'object', properties: { id: { type: 'number' } } } }
},
handler: async (req, reply) => { /*...*/ }
});
3、Hooks(生命周期钩子)
常见 hooks(执行顺序):
- onRequest --- 在请求到达时执行(可用于认证、速率限制)。
- preParsing --- 原始 body 解析前。
- preValidation --- 校验前(可修改请求)。
- preHandler --- 校验后、handler 前(常用于权限)。
- preSerialization --- 响应序列化前(可处理数据)。
- onSend --- 响应发送前(最后改 header)。
- onResponse --- 响应完成后(用于日志、清理)。
- onTimeout / onError 等特殊钩子。
示例:
cpp
fastify.addHook('onRequest', async (req, reply) => {
// 认证
});
4、Decorators(扩展实例/请求/回复)
- fastify.decorate(name, value):添加到 Fastify 实例(可在插件中注入)。
- fastify.decorateRequest('foo', null) / fastify.decorateReply('bar', null):为 request/reply 增加方法/字段。
【注意】:装饰要与 encapsulation 协调,避免跨插件冲突。
示例:
cpp
fastify.decorate('utils', { uuid: () => '...' });
fastify.decorateRequest('user', null);
5、Encapsulation(封装)
- 插件之间默认是封装的:子插件的 decorate 不会泄露给父插件之外的插件,除非你显式设置 fastify.register() 的 options。
- 这是 Fastify 防止全局污染的核心机制:你可以为每个模块创建独立上下文(依赖注入、安全隔离)。
四、插件系统(最重要的机制)
1、注册插件
cpp
fastify.register(require('@fastify/sqlite'), { dbFile: ':memory:' });
注册后插件可以使用 fastify.decorate 注入 db 实例或其他工具。
2、fastify-plugin
用于将一个函数标记为 Fastify 插件(并可设置依赖)。
示例:
cpp
const fp = require('fastify-plugin');
module.exports = fp(async (fastify, opts) => {
fastify.decorate('service', new Service(opts));
}, { name: 'my-service', dependencies: ['@fastify/sqlite'] });
3、autoload(自动加载)
fastify-autoload 可以按照目录结构自动加载插件、路由,适合大型项目约定成俗的结构。
五、性能相关(为什么 Fastify 快?如何优化)
1、性能来源
- JSON 序列化使用 fast-json-stringify,针对 schema 生成快速序列化函数(比 JSON.stringify 在某些场景快)。
- Schema 驱动减少运行期校验开销(编译一次复用)。
- 更少中间件抽象层,低 overhead。
2、性能优化建议
- 使用 schema:为请求和响应都加 schema,能显著提速。
- 避免在热路由上做大量同步工作:同步计算会阻塞事件循环。
- 使用 reply.serializer(自定义序列化)仅在必要时。
- 复用单例资源(DB 连接池),但注意封装作用域。
- 开启 HTTP keep-alive、合理设置 maxSockets(在客户端或代理中)。
- 批量响应/压缩:使用 @fastify/compress 启用 gzip/brotli。
- 在高并发下使用 cluster 或进程管理(PM2 / Kubernetes)扩展。
3、Threadpool 与 CPU 密集
- Fastify 本身是单线程 JS。CPU 耗时操作应用 worker_threads 或把任务下放给后台微服务。
六、TypeScript 与 Fastify(企业级要点)
Fastify 对 TypeScript 支持很好,但要注意类型扩展与插件的类型。
1、基本 TypeScript 快速示例
cpp
import Fastify from 'fastify';
const fastify = Fastify({ logger: true });
fastify.get('/', async (request, reply) => {
return { hello: 'world' };
});
2、类型扩展(decorate、plugin)
如果插件 decorate 了 fastify.foo,需在类型声明中扩展 FastifyInstance 接口:
cpp
declare module 'fastify' {
interface FastifyInstance {
service: MyService;
}
}
对于 request.body 等,使用泛型指定 route 的 schema types:
cpp
fastify.post<{ Body: { name: string } }>('/user', async (request, reply) => {
const name = request.body.name;
});
3、推荐工具链
- ts-node-dev(开发阶段)
- 构建到 JS(tsc / esbuild)用于生产
- 使用 fastify-cli 创建 TS 项目模板
七、路由与分层架构(最佳实践)
1、项目结构(建议)
cpp
src/
server.ts
plugins/
db.ts
auth.ts
routes/
users/
index.ts // 注册子路由
handlers.ts
schema.ts
services/
userService.ts
utils/
types/
使用 fastify-autoload 自动加载 plugins 和 routes,配合 fastify-plugin 做依赖注入。
2、路由封装示例
routes/users/index.ts:
cpp
import { FastifyPluginAsync } from 'fastify';
import handlers from './handlers';
import schema from './schema';
const users: FastifyPluginAsync = async (fastify) => {
fastify.get('/', { schema: schema.list }, handlers.list);
fastify.get('/:id', { schema: schema.get }, handlers.get);
};
export default users;
八、安全(必做项)
- 使用 @fastify/helmet 添加安全头(CSP、X-Frame、XSS)。
- 使用 @fastify/rate-limit 防止滥用(DoS、暴力破解)。
- 使用 @fastify/cors 配置 CORS 白名单。
- 校验输入(schema)以防注入攻击。
- 在生产中禁用详细错误输出,使用统一错误结构(error handler)。
示例:
cpp
fastify.register(require('@fastify/helmet'));
fastify.register(require('@fastify/rate-limit'), { max: 100, timeWindow: '1 minute' });
fastify.register(require('@fastify/cors'), { origin: ['https://your.app'] });
九、错误处理与日志
- 使用 setErrorHandler 自定义错误格式与日志:
cpp
fastify.setErrorHandler((error, request, reply) => {
request.log.error(error);
reply.status(error.statusCode || 500).send({ error: error.message });
});
- 内置 logger 使用 pino,性能优秀。生产建议把日志输出到 stdout 并由日志聚合系统采集。
十、测试(单元、集成、端到端)
推荐使用 tap(Fastify 官方示例)或 Jest + supertest。fastify.inject() 可以直接模拟请求,不需要启动网络端口,非常适合单元/集成测试。
示例(tap):
cpp
const t = require('tap');
const Fastify = require('fastify');
t.test('GET /', async t => {
const app = Fastify();
app.get('/', async () => ({ ok: true }));
const res = await app.inject({ method: 'GET', url: '/' });
t.equal(res.statusCode, 200);
t.same(JSON.parse(res.payload), { ok: true });
await app.close();
});
十一、常用与推荐插件(企业级清单)
- @fastify/helmet --- 安全头
- @fastify/cors --- CORS
- @fastify/compress --- gzip/brotli
- @fastify/jwt --- JWT 认证
- @fastify/oauth2 --- OAuth2 客户端
- @fastify/rate-limit --- 限流
- @fastify/swagger / @fastify/openapi-glue --- 自动生成 API 文档
- @fastify/sqlite, @fastify/postgres --- DB 连接
- fastify-autoload --- 自动加载插件/路由
- fastify-plugin --- 标记插件
- fastify-sensible --- 常用响应工具(httpErrors 等)
- fastify-formbody --- 解析 form body
- fastify-static --- 静态文件
- fastify-multipart --- 文件上传(stream 支持)
十二、Express 到 Fastify 的迁移实务(要点)
- 路由语法类似,但要改造 middleware:Express 中间件需用 fastify-express 或改写为 Fastify hooks/plugins。
- 注意:Express 全局中间件在 Fastify 中要转成 hook 或封装插件。
- req/res 对象不同,Fastify 提供 request.raw 和 reply.raw 访问原生 node 对象。
- 推荐逐步迁移:把路由逐个转换为 Fastify plugin,使用 fastify.register() 提高可维护性。
十三、部署与扩容(生产实践)
- 多进程:使用 cluster、PM2 或容器编排(K8s)将应用扩展到多核。
- 反向代理:通常前面放 Nginx / Envoy 做 TLS 终端、静态缓存、负载均衡。
- 资源监控:pino 日志 + Prometheus 指标导出(prom-client)+ Grafana。
- 健康探针:提供 /healthz readiness 和 liveness endpoints。
- 容器镜像:使用多阶段构建,生产镜像只包含运行时产物;用非 root 用户运行。
示例 Dockerfile:
cpp
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app ./
ENV NODE_ENV=production
RUN npm ci --production
USER node
CMD ["node", "dist/index.js"]
十四、监控指标 & 健康检查(建议)
导出常见指标(响应时间、错误率、event loop lag、heap usage),并在 K8s HPA 中使用自定义指标。
快速导出 event loop lag:
cpp
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay();
h.enable();
setInterval(() => {
// expose h.mean/h.max to prometheus
}, 5000);
十五、常见问题与排查指南
- 高延迟但 CPU 很低:可能外部依赖慢(DB、HTTP),加超时与熔断,检查连接池。
- 内存泄漏 / OOM:进行 heapdump 分析,检查全局缓存、未关闭的连接与未清的定时器。
- 大量 502/504:代理超时、后端资源耗尽或死锁。检查 Nginx 配置与 keepalive。
- schema 校验报错:查看 schema 的 compiled errors,注意 additionalProperties 默认行为。
- 插件冲突:检查 encapsulation,是否意外 decorate 全局变量名重复。
十六、性能调优 checklist(落地)
- 使用 schema(请求 + 响应)。
- 在高频 API 使用 response.schema + fast-json-stringify 的序列化优势。
- 避免常见阻塞(同步 IO、大对象 JSON.stringify)。
- 启用 @fastify/compress 并选择合适压缩算法(brotli 在静态资源上优异)。
- 使用 pino 并输出到 stdout(不会阻塞主线程)。
- 对大文件上传使用 stream(fastify-multipart)。
- 将 CPU 密集任务用 worker_threads 容器化或微服务化。
- 在 K8s 中设置合理的资源 requests/limits,使用 HPA。
十七、实战示例:一个带 Auth、DB、Swagger 的项目骨架(关键代码片段)
src/server.ts:
cpp
import Fastify from 'fastify';
import autoload from 'fastify-autoload';
import path from 'path';
const fastify = Fastify({ logger: true });
fastify.register(require('@fastify/helmet'));
fastify.register(require('@fastify/cors'), { origin: true });
fastify.register(require('@fastify/compress'));
fastify.register(autoload, { dir: path.join(__dirname, 'plugins') });
fastify.register(autoload, { dir: path.join(__dirname, 'routes') });
fastify.listen({ port: 3000 })
.then(() => fastify.log.info('Server started'));
src/plugins/db.ts:
cpp
import fp from 'fastify-plugin';
import { Database } from 'some-db-lib';
export default fp(async function (fastify, opts) {
const db = new Database(opts);
fastify.decorate('db', db);
fastify.addHook('onClose', async () => { await db.close(); });
});
src/routes/users/index.ts:
cpp
import fp from 'fastify-plugin';
export default async function (fastify) {
fastify.get('/users', {
schema: { response: { 200: { type: 'array', items: { type: 'object' } } } }
}, async (req, reply) => {
return await fastify.db.getUsers();
});
}
十八、Fastify 与其他框架对比(简要)
- Express:生态大、学习门槛低,但性能与 schema 支持较弱。迁移到 Fastify 可获得性能和类型优势。
- Koa:语法优雅、基于 async/await,中间件更简洁;Fastify 更注重性能与插件封装。
- NestJS:企业级架构(DI、模块化)。Nest 可以选择 Fastify 作为底层 HTTP adapter,得到两者优点。