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

4. 您实际得到的结果?

限流ulule/limiter 包进行封装时,CheckRate 检测请求是否超额,取限流结果提示报错

讨论数量: 1

gin.Context是一个类型,而context.Context是一个接口,它具有一个方法Value,用于从上下文中检索值。

要将gin.Context转换为context.Context,您可以使用context.WithValue方法:

ctx := context.WithValue(context.Background(), "GinContext", c)

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!