Fastify使用Ajv时避免重复创建函数的最佳实践及代码疑问
Fastify验证/序列化避免重复创建函数的最佳实践
问题背景
⚠ 安全提示
请将 Schema 定义视为应用代码。验证和序列化功能会通过new Function()动态执行代码,使用用户提供的 Schema 存在安全风险。
另外,尽管 Fastify 支持 Ajv 的$async特性,但不应将其作为首要验证策略。该选项用于在验证过程中访问数据库,这可能导致应用遭受拒绝服务攻击。如果需要执行异步任务,请在验证完成后使用 Fastify 的钩子(如preHandler)。
用户当前代码示例:
const PostMovieBody = { type: 'object', properties: { title: { type: 'string' }, releaseYear: { type: 'integer', minimum: 1878 }, }, } app.post('/movie', { schema: { // 引用 Schema body: PostMovieBody, '2xx': { type: 'object', properties: { value: { type: 'string' }, otherValue: { type: 'boolean' } } }, }, })
用户疑问:该示例是否会每次创建新函数?若是,该如何避免?使用验证/序列化时,避免每次创建新函数的最佳实践是什么?
解答
你的代码是否会重复创建函数?
不会。Fastify 内部会对传入的 Schema 进行缓存,在应用启动阶段就会基于 Schema 生成对应的验证/序列化函数,之后每次请求都会复用这些预生成的函数,不会在每次请求时重新创建。
避免重复创建函数的最佳实践
- 复用 Schema 对象:像你代码中这样把 Schema 定义为全局常量(如
PostMovieBody),而不是在路由配置内部动态生成 Schema 对象。这样 Fastify 能准确识别同一个 Schema,避免重复编译。 - 依赖默认缓存机制:Fastify 默认使用的 Ajv 验证器本身自带缓存功能,只要你不每次传入全新的匿名 Schema 对象,就能自动命中缓存,避免重复生成函数。
- 禁止动态修改 Schema:如果在运行时动态修改已定义的 Schema 内容,会触发 Fastify/Ajv 重新编译函数。尽量在应用启动前就确定好所有 Schema 的结构。
- 使用 Schema 引用($ref):对于重复使用的 Schema 片段,用
$ref引用集中管理的 Schema,既减少代码冗余,又能确保同一片段只被编译一次。示例:// 集中定义可复用 Schema const schemas = { PostMovieBody: { $id: 'postMovieBody', type: 'object', properties: { title: { type: 'string' }, releaseYear: { type: 'integer', minimum: 1878 }, } } } // 注册所有 Schema 到 Fastify app.addSchema(schemas.PostMovieBody) // 在路由中引用 app.post('/movie', { schema: { body: { $ref: 'postMovieBody' }, // ... 其他 Schema 配置 } }) - 杜绝动态生成 Schema:不要在请求处理过程或路由注册时,根据用户输入等动态拼接 Schema。这不仅会触发重复编译,还违反安全提示中「不可使用用户提供的 Schema」的要求。
内容的提问来源于stack exchange,提问作者lambdamaster
相关产品推荐
相关产品推荐

