Fastify 简介
Fastify 是一个高性能的 Node.js Web 框架,专注于提供卓越的性能和开发体验。它由 Matteo Collina 创立,设计目标是成为最快的 Web 框架之一,同时保持开发的简洁性和灵活性。
核心特点
- 高性能:Fastify 是目前最快的 Node.js Web 框架之一,处理请求的速度非常快。
- 低开销:框架本身的开销很小,意味着更多的资源可以用于处理业务逻辑。
- 插件系统:提供了强大的插件系统,便于扩展功能。
- 请求验证:内置请求验证功能,确保数据的正确性和安全性。
- 序列化:高效的响应序列化,减少网络传输时间。
- 日志记录:内置结构化日志系统,便于调试和监控。
- 类型支持:良好的 TypeScript 支持,提供类型安全。
- 生态系统:丰富的官方和社区插件,满足各种需求。
安装与配置
安装 Fastify
使用 npm 或 yarn 安装 Fastify:
# 使用 npm 安装
npm install fastify
# 使用 yarn 安装
yarn add fastify创建第一个 Fastify 应用
创建一个简单的 Fastify 应用,响应 HTTP 请求:
// app.js
const fastify = require('fastify')({ logger: true });
// 定义路由
fastify.get('/', async (request, reply) => {
return { hello: 'world' };
});
// 启动服务器
const start = async () => {
try {
await fastify.listen({ port: 3000 });
fastify.log.info(`Server running at http://localhost:3000`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();运行应用:
node app.js核心概念
路由
Fastify 的路由系统简洁而强大,支持多种 HTTP 方法和参数类型。
// 基本路由
fastify.get('/hello', async (request, reply) => {
return { message: 'Hello World!' };
});
// 带参数的路由
fastify.get('/users/:id', async (request, reply) => {
const { id } = request.params;
return { userId: id };
});
// 带查询参数的路由
fastify.get('/search', async (request, reply) => {
const { q } = request.query;
return { query: q };
});
// POST 请求
fastify.post('/users', async (request, reply) => {
const user = request.body;
return { user };
});请求验证
Fastify 内置了请求验证功能,使用 JSON Schema 验证请求数据:
// 定义验证模式
const userSchema = {
type: 'object',
required: ['name', 'email'],
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' },
age: { type: 'integer', minimum: 18 }
}
};
// 使用验证模式
fastify.post('/users', {
schema: {
body: userSchema
}
}, async (request, reply) => {
const user = request.body;
return { user };
});插件系统
Fastify 的插件系统是其核心特性之一,允许开发者模块化代码并扩展功能:
// 创建插件
const myPlugin = (fastify, options, done) => {
fastify.get('/plugin', async (request, reply) => {
return { plugin: 'Hello from plugin!' };
});
done();
};
// 注册插件
fastify.register(myPlugin);
// 带选项的插件
const pluginWithOptions = (fastify, options, done) => {
fastify.get('/plugin-with-options', async (request, reply) => {
return { message: options.message };
});
done();
};
// 注册带选项的插件
fastify.register(pluginWithOptions, { message: 'Hello from plugin with options!' });中间件
Fastify 支持 Express 和 Connect 风格的中间件:
// 使用中间件
fastify.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
});
// 路由级中间件
fastify.get('/protected', {
preHandler: (request, reply, done) => {
// 验证逻辑
const token = request.headers.authorization;
if (!token) {
reply.status(401).send({ error: 'Unauthorized' });
return;
}
done();
}
}, async (request, reply) => {
return { message: 'Protected route' };
});钩子(Hooks)
Fastify 提供了多种生命周期钩子,用于在请求处理的不同阶段执行代码:
// 全局钩子
fastify.addHook('onRequest', (request, reply, done) => {
console.log('Request received');
done();
});
fastify.addHook('preHandler', async (request, reply) => {
console.log('Before handling request');
});
fastify.addHook('onResponse', (request, reply, done) => {
console.log('Response sent');
done();
});
// 路由级钩子
fastify.get('/hooked', {
preHandler: async (request, reply) => {
console.log('Route-specific preHandler hook');
}
}, async (request, reply) => {
return { message: 'Hooked route' };
});错误处理
Fastify 提供了统一的错误处理机制:
// 全局错误处理
fastify.setErrorHandler((error, request, reply) => {
fastify.log.error(error);
reply.status(500).send({ error: 'Internal Server Error' });
});
// 路由级错误处理
fastify.get('/error', async (request, reply) => {
throw new Error('Something went wrong');
});
// 自定义错误
class CustomError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
fastify.get('/custom-error', async (request, reply) => {
throw new CustomError('Custom error message', 400);
});
// 处理自定义错误
fastify.setErrorHandler((error, request, reply) => {
const statusCode = error.statusCode || 500;
reply.status(statusCode).send({ error: error.message });
});实用案例分析
构建 RESTful API
下面是一个使用 Fastify 构建 RESTful API 的示例,实现了基本的 CRUD 操作。
项目结构
├── app.js
├── routes/
│ └── users.js
├── services/
│ └── userService.js
└── package.json代码实现
- 用户服务 (
services/userService.js):
// 模拟用户数据
let users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
];
// 获取所有用户
const getUsers = () => users;
// 根据 ID 获取用户
const getUserById = (id) => users.find(user => user.id === parseInt(id));
// 创建新用户
const createUser = (user) => {
const newUser = {
id: users.length + 1,
...user
};
users.push(newUser);
return newUser;
};
// 更新用户
const updateUser = (id, user) => {
const index = users.findIndex(user => user.id === parseInt(id));
if (index === -1) return null;
users[index] = { ...users[index], ...user };
return users[index];
};
// 删除用户
const deleteUser = (id) => {
const index = users.findIndex(user => user.id === parseInt(id));
if (index === -1) return null;
users.splice(index, 1);
return { message: 'User deleted successfully' };
};
module.exports = {
getUsers,
getUserById,
createUser,
updateUser,
deleteUser
};- 用户路由 (
routes/users.js):
const userService = require('../services/userService');
// 用户验证模式
const userSchema = {
type: 'object',
required: ['name', 'email'],
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' }
}
};
// 更新用户验证模式
const updateUserSchema = {
type: 'object',
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' }
}
};
// 定义路由
const userRoutes = (fastify, options, done) => {
// 获取所有用户
fastify.get('/users', async (request, reply) => {
const users = userService.getUsers();
return users;
});
// 获取单个用户
fastify.get('/users/:id', async (request, reply) => {
const user = userService.getUserById(request.params.id);
if (!user) {
reply.status(404).send({ error: 'User not found' });
return;
}
return user;
});
// 创建用户
fastify.post('/users', {
schema: {
body: userSchema
}
}, async (request, reply) => {
const newUser = userService.createUser(request.body);
reply.status(201).send(newUser);
});
// 更新用户
fastify.put('/users/:id', {
schema: {
body: updateUserSchema
}
}, async (request, reply) => {
const updatedUser = userService.updateUser(request.params.id, request.body);
if (!updatedUser) {
reply.status(404).send({ error: 'User not found' });
return;
}
return updatedUser;
});
// 删除用户
fastify.delete('/users/:id', async (request, reply) => {
const result = userService.deleteUser(request.params.id);
if (!result) {
reply.status(404).send({ error: 'User not found' });
return;
}
reply.status(200).send(result);
});
done();
};
module.exports = userRoutes;- 主应用 (
app.js):
const fastify = require('fastify')({ logger: true });
const userRoutes = require('./routes/users');
// 注册路由插件
fastify.register(userRoutes);
// 健康检查路由
fastify.get('/health', async (request, reply) => {
return { status: 'ok' };
});
// 全局错误处理
fastify.setErrorHandler((error, request, reply) => {
fastify.log.error(error);
const statusCode = error.statusCode || 500;
reply.status(statusCode).send({ error: error.message || 'Internal Server Error' });
});
// 启动服务器
const start = async () => {
try {
await fastify.listen({ port: 3000 });
fastify.log.info(`Server running at http://localhost:3000`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();测试 API
使用 curl 或 Postman 测试 API:
# 获取所有用户
curl http://localhost:3000/users
# 获取单个用户
curl http://localhost:3000/users/1
# 创建用户
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"name": "王五", "email": "wangwu@example.com"}'
# 更新用户
curl -X PUT http://localhost:3000/users/1 -H "Content-Type: application/json" -d '{"name": "张三更新", "email": "zhangsan-updated@example.com"}'
# 删除用户
curl -X DELETE http://localhost:3000/users/1
# 健康检查
curl http://localhost:3000/health数据库集成
Fastify 支持多种数据库,包括 PostgreSQL、MySQL、MongoDB 等。下面以 PostgreSQL 为例,展示如何集成数据库。
安装依赖
# 安装 PostgreSQL 客户端
npm install pg
# 安装 Fastify PostgreSQL 插件
npm install @fastify/postgres配置数据库连接
const fastify = require('fastify')({ logger: true });
// 注册 PostgreSQL 插件
fastify.register(require('@fastify/postgres'), {
connectionString: 'postgres://username:password@localhost:5432/database'
});
// 使用数据库连接
fastify.get('/users', async (request, reply) => {
const client = await fastify.pg.connect();
try {
const { rows } = await client.query('SELECT * FROM users');
return rows;
} finally {
client.release();
}
});
// 启动服务器
const start = async () => {
try {
await fastify.listen({ port: 3000 });
fastify.log.info(`Server running at http://localhost:3000`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();性能优化
Fastify 本身已经非常快,但还有一些方法可以进一步优化性能:
1. 使用 JSON Schema 验证
使用 JSON Schema 验证请求和响应可以提高性能,因为 Fastify 会编译 Schema 为高效的验证函数:
// 定义响应 Schema
const responseSchema = {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string' },
email: { type: 'string', format: 'email' }
}
};
// 使用响应 Schema
fastify.get('/users/:id', {
schema: {
response: {
200: responseSchema
}
}
}, async (request, reply) => {
// 处理请求
});2. 使用序列化钩子
对于复杂的响应对象,可以使用序列化钩子来优化序列化过程:
fastify.addHook('preSerialization', (request, reply, payload, done) => {
// 优化序列化逻辑
if (Array.isArray(payload)) {
payload = payload.map(item => ({
id: item.id,
name: item.name,
// 只包含必要的字段
}));
}
done(null, payload);
});3. 使用 Redis 作为缓存
对于频繁访问的数据,可以使用 Redis 作为缓存:
# 安装 Redis 客户端
npm install redis
# 安装 Fastify Redis 插件
npm install @fastify/redis// 注册 Redis 插件
fastify.register(require('@fastify/redis'), {
host: 'localhost',
port: 6379
});
// 使用 Redis 缓存
fastify.get('/users/:id', async (request, reply) => {
const { id } = request.params;
const cacheKey = `user:${id}`;
// 尝试从缓存获取
const cachedUser = await fastify.redis.get(cacheKey);
if (cachedUser) {
return JSON.parse(cachedUser);
}
// 从数据库获取
const user = await getUserFromDatabase(id);
// 存入缓存
await fastify.redis.set(cacheKey, JSON.stringify(user), 'EX', 3600);
return user;
});总结
Fastify 是一个高性能、低开销的 Node.js Web 框架,它提供了简洁而强大的 API,同时保持了卓越的性能。通过本教程,你应该已经了解了 Fastify 的核心概念和基本用法,包括路由、请求验证、插件系统、中间件、钩子和错误处理等。
Fastify 的插件系统和生态系统使其非常灵活,可以适应各种应用场景,从简单的 API 到复杂的微服务。它的高性能特性使其成为构建需要处理大量请求的应用的理想选择。
要深入学习 Fastify,建议查阅 官方文档 和实践更多的项目案例,以掌握其高级特性和最佳实践。Fastify 的社区也非常活跃,有大量的插件和资源可供参考。