如何在Fastify中安全高效使用Schema校验与序列化?
Fastify中Ajv与fast-json-stringify的选择及使用指南
官方文档提示
将Schema定义视为应用代码。校验和序列化功能会通过
new Function()动态执行代码,因此不要使用用户提供的Schema,这存在安全风险。更多细节可参考Ajv和fast-json-stringify。此外,不要将Ajv的
$async特性作为首要校验策略。该特性用于在校验过程中访问数据库,这可能导致应用遭受拒绝服务攻击。如果需要执行异步任务,请在校验完成后使用Fastify的钩子(比如preHandler)。
你的疑问
我正在学习Fastify的Schema校验机制,想知道应该选择Ajv还是fast-json-stringify,以及如何在自己的Schema写法中使用它们?已经掌握了两种Schema写法,但不确定该选哪个库实现安全高效的JSON处理。
一、不用二选一:两者职责不同
Ajv和fast-json-stringify是Fastify默认集成的工具,各司其职:
- Ajv:专门负责请求/响应的Schema校验——比如检查请求参数格式是否合规、返回的响应数据是否符合定义结构
- fast-json-stringify:专门负责响应数据的高效序列化——基于Schema把JS对象转成JSON字符串,性能比原生
JSON.stringify高很多
Fastify会自动协调两者工作:只要你定义了Schema,Ajv会自动完成校验,fast-json-stringify会自动用Schema做序列化优化,完全不需要你手动切换。
二、两种Schema写法的实际应用
1. 路由局部Schema(单路由专用)
你写的第一种Schema是给单个路由定义响应规则,Fastify会自动:
- 用Ajv校验该路由返回的200状态码响应,确保是包含
name(字符串)和age(数字)对象的数组 - 用fast-json-stringify基于这个Schema做序列化,提升响应速度
代码示例:
schema: { response: { 200: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'number' } } } } } }
2. 全局复用Schema(多路由共享)
第二种用fastify.addSchema()定义的全局Schema,会被Ajv和fast-json-stringify同时识别:
- 当你在路由Schema中用
$ref引用它时,Ajv会用它校验请求/响应数据 - 序列化引用该Schema的响应时,fast-json-stringify同样会做性能优化
代码示例:
// 定义全局可复用的Schema fastify.addSchema({ $id: "createUseSchema", type: "object", required: ["name"], properties: { name: { type: "string", }, }, }); // 在路由中引用全局Schema fastify.post('/user', { schema: { body: { $ref: "createUseSchema" } // 校验请求体是否符合该Schema } }, async (req, res) => { res.send({ status: 'ok', data: req.body }); });
三、安全高效的核心注意事项
- 绝对禁止使用用户提供的Schema:因为Ajv和fast-json-stringify会动态执行代码,用户可控的Schema可能注入恶意逻辑
- 不要用Ajv的
$async做校验:如果需要异步操作(比如查数据库验证用户),放到preHandler钩子中执行,避免在校验阶段阻塞或引发DoS攻击 - Schema只写必要规则:冗余的字段和规则会降低校验和序列化性能,还容易引发匹配错误
内容的提问来源于stack exchange,提问作者stackcall01
相关产品推荐
相关产品推荐

