ulule/limiter 包进行封装时报错:无法将 ‘c’ (类型 *gin.Context) 用作类型 context.Context类型未实现 ‘context.Context’
1. 运行环境
go version: go1.17 darwin/amd64
gin version: v1.8.2
ulule/limiter/v3: v3.10.0
2. 问题描述?
// CheckRate 检测请求是否超额
func CheckRate(c *gin.Context, key string, formatted string) (limiterlib.Context, error) {
// 1. 实例化依赖的 limiter 包的 limiter.Rate 对象
var context limiterlib.Context
rate, err := limiterlib.NewRateFromFormatted(formatted)
if err != nil {
logger.LogIf(err)
return context, err
}
// 2. 初始化存储,使用我们程序里共用的 redis.Redis 对象
store, err := sredis.NewStoreWithOptions(redis.Redis.Client, limiterlib.StoreOptions{
// 为 limiter 设置前缀,保持 redis 里数据的整洁
Prefix: config.GetString("app.name") + ":limiter",
})
if err != nil {
logger.LogIf(err)
return context, err
}
// 3. 使用上面的初始化的 limiter.Rate 对象和存储对象
limiterObj := limiterlib.New(store, rate)
// 4. 获取限流的结果
if c.GetBool("limiter-once") {
// Peek() 取结果,不增加访问次数
return limiterObj.Peek(c, key)
} else {
// 确保多个路由组里调用 LimitIP 进行限流时,只增加一次访问次数。
c.Set("limiter-once", true)
// Get() 取结果且增加访问次数
return limiterObj.Get(c, key)
}
}
limiterObj.Peek(c, key) 提示
无法将 ‘c’ (类型 *gin.Context) 用作类型 context.Context类型未实现 ‘context.Context’ 需要方法: Value(key interface{}) interface{}具有方法: Value(key any) any
跳转到Peek方法的代码是
// Peek returns the limit for given identifier, without modification on current values.
func (limiter *Limiter) Peek(ctx context.Context, key string) (Context, error) {
return limiter.Store.Peek(ctx, key, limiter.Rate)
}
3. 您期望得到的结果?
怎么实现*gin.Context to context.Context
gin.Context是一个类型,而context.Context是一个接口,它具有一个方法Value,用于从上下文中检索值。
要将gin.Context转换为context.Context,您可以使用context.WithValue方法:
ctx := context.WithValue(context.Background(), "GinContext", c)