缓存验证规则
使用schema.create
方法创建的模式首先编译为可执行函数,然后执行以根据定义的规则验证数据。
在验证开始之前,编译过程确实需要几毫秒。但是,根据你的性能预期,你可能需要考虑缓存已编译的模式,因此不要为每个请求支付编译费用。
使用cacheKey
你可以通过定义唯一的cacheKey
来缓存模式。你可以使用任何方法生成此缓存密钥,也可以在 HTTP 请求期间依赖ctx.routeKey
。
await request.validate({
schema: schema.create({...}),
cacheKey: ctx.routeKey,
})
- 对
request.validate
的第一次调用将编译模式并将输出保存为对cacheKey
的引用。 - 在
cacheKey
相同之前,验证器不会重新编译模式。
缓存注意事项
任何形式的缓存都不是免费的,模式缓存也是如此。如果你的架构依赖于运行时值,那么缓存架构将不会提供所需的结果。考虑以下示例:
- 你正在创建一个接受用户 state 和他们的 city 的表单。
- 在
cacheKey
相同之前,验证器不会重新编译模式。
/**
* 缓存注意事项
*/
const STATES = []
const CITIES = {}
export default class AddressValidator {
public selectedState = this.ctx.request.input('state') // 👈
public schema = schema.create({
state: schema.enum(STATES),
city: schema.enum(CITIES[this.selectedState] || [])
})
}
如果你查看上面的示例,city
的枚举选项取决于selectedState
并且可能随每个 HTTP 请求而变化。
但是,由于我们启用了模式缓存。在第一个请求之后的 enum 选项将被缓存,并且即使用户选择了不同的状态也不会改变。
现在你已经了解了缓存的工作原理。让我们探索在验证模式中使用动态数据的一些不同方法。
放弃缓存
第一种选择是放弃缓存。这将给请求增加几毫秒的延迟,但却为你在模式定义中使用运行时值提供了最直接的 API。
创建唯一密钥
考虑到上面的例子,你可以将选择的状态附加到 cacheKey
中,因此每个状态都会有一个缓存模式的副本。例如:
export default class AddressValidator {
public selectedState = this.ctx.request.input('state')
public schema = schema.create({
state: schema.enum(STATES),
city: schema.enum(CITIES[this.selectedState] || [])
})
public cacheKey = `${this.ctx.routeKey}-${selectedState}`
}
上述方法也有其自身的缺点。例如,如果有 37 种状态,那么同一模式的缓存副本将有 37 个,只是略有不同。此外,如果需要多个动态值,这个数字将呈指数增长。
放弃缓存要比缓存太多略有变化的模式要好。
使用 Ref
Refs 给你两全其美。你仍然可以缓存模式并引用其中的运行时值。下面是一个例子:
export default class AddressValidator {
public selectedState = this.ctx.request.input('state')
public refs = schema.refs({
cities: CITIES[this.selectedState] || []
})
public schema = schema.create({
state: schema.enum(STATES),
city: schema.enum(this.refs.cities)
})
}
不是直接引用 CITIES[this.selectedState]
,而是将其移动到 schema.refs
对象,然后从那里开始,CITIES 将在运行时被拾取,而无需重新编译模式。
注:Ref只有在 验证规则 或 模式类型 支持它们时才起作用。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。