利用Redis对含有分页参数的API接口做调用次数限制

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 利用Redis对含有分页参数的API接口做调用次数限制

 背景 - 限制接口调用次数:

       提供内部调用的全量拉取数据接口,以用户appid作为维度区分,一定时间段内(比如1小时),查询某一接口的appid和limit、offset等组合参数只能查询一次,多次查询相同组合参数则返回错误值。

思路:

       采用string类型,key就是模块名:api_limiter_xxx(根据需要自定义key名称),value就是当前可以访问的页数(每次访问成功都自增1)。第一次访问某接口时,若key不存在,那么就添加;若存在,则获取当前redis中对应key的"页数值",并与入参Limit和Offset计算后的页数结果进行比较,若相等则调用成功,反之调用失败。

其中,在设置key和value的时候也要设置"过期时间"。所以关键在于 SETNX 的使用,若存在,则匹配计算的页数与redis中的计数器页数是否相等,若不存在,则设置kv。

注意:其中每次set key的值的时候,过期时间的处理。这里在set之前先通过TTL获取key剩余的过期时间,然后set时再带入接下来剩余的时间即可,避免每次都重新设置固定的过期时间。

    1. 初始时,redisPageCnt = 1
    2. 首次调用接口时,Limit=10,Offset=0,calculateCnt = (Limit + Offset) / Limit = 1;redisPageCnt=1
    3. 此时 calculateCnt = redisPageCnt 相等,redisPageCnt++,redisPageCnt = 2
    4. 再次调用接口时,Limit=10,Offset=10,calculateCnt = (Limit + Offset) / Limit = 2;redisPageCnt=2
    5. 此时 calculateCnt = redisPageCnt 相等,redisPageCnt++,redisPageCnt = 3
    6. ...

           这样的话就可以按页数从前往后递增,每页在限制的超时时间内(1小时)访问一次。在key的超时时间内,访问过的页数也不能再次访问,除非redis中的key超时时间失效。

    请求示例:

    var req = TestReq{ Appid: 1256299843, Limit: 10, Offset: 20, }

    packagemainimport (
    "fmt""strconv""time""github.com/go-redis/redis")
    // 限流:针对含有分页参数的接口,对于不同"Limit和Offset"组合做限制,避免某个用户大量请求影响后台服务处理其他正常请求// 示例://  var req = TestReq{//      Appid:  1256299843,//      Limit:  10,//      Offset: 20,//  }typeTestReqstruct {
    Appiduint64LimitintOffsetint}
    funcAPILimiter(reqTestReq) (errerror) {
    ifreq.Limit!=10 { // 校验入参,暂时写死,根据情况修改fmt.Println("req.Limit format err: ")
    // return response ...return    }
    redisCli :=redis.NewClient(&redis.Options{
    Addr:     "xxx.xxx.xxx.xxx:3306", // ip:portPassword: "yundingyd",
    PoolSize: 10,
        })
    // pong, err := redisCli.Ping().Result()// 不存在 -> 初始化;存在 -> 不处理redisKey :="api_limiter_"+strconv.FormatUint(req.Appid, 10)
    isOk, err :=redisCli.SetNX(redisKey, 1, time.Hour).Result() // 限制超时1小时,Result()针对不同命令自动转换对应结果iferr!=nil&&err!=redis.Nil&&isOk==false {
    fmt.Println("APILimiter SetNX err: ", err)
    // return response ...return    }
    calculatePageCnt := (req.Limit+req.Offset) /req.LimitredisPageCnt, err :=redisCli.Get(redisKey).Int()
    iferr!=nil&&err!=redis.Nil&&isOk==false {
    fmt.Println("APILimiter redisCli.Get err: ", err)
    // return response ...return    }
    ifcalculatePageCnt!=redisPageCnt {
    fmt.Printf("接口调用失败:当前Limit和Offset对应的页数无效: limit=%d, offset=%d, calculateCnt=%d, redisPageCnt=%d\n", req.Limit, req.Offset, calculatePageCnt, redisPageCnt)
    // return response ...return    }
    deferfunc() {
    iferr==nil { // 具体的业务逻辑,期间可能会产生err,只有err为空时才执行以下逻辑~// 先查询当前key的剩余过期时间timeDuration, err :=redisCli.TTL(redisKey).Result()
    iferr!=nil&&err!=redis.Nil {
    fmt.Println("redisCli.TTL err: ", err)
    // return response ...return            }
    // 再设置当前key的剩余过期时间isOk, err :=redisCli.Set(redisKey, redisPageCnt+1, timeDuration).Result() // page + 1iferr!=nil&&err!=redis.Nil&&isOk!="OK" {
    fmt.Println("redisCli.Set err: ", err)
    // return response ...return            }
    fmt.Println("接口调用成功!!!")
            }
        }()
    // 具体的业务逻辑(期间可能会产生err,除非期间err为nil,否则defer函数不执行 page+1 等操作):// ...return}
    funcmain() {
    varreq=TestReq{
    Appid:  1256299843,
    Limit:  10,
    Offset: 20,
        }
    err :=APILimiter(req)
    iferr!=nil {
    fmt.Println("APILimiter err: ", err)
    return    }
    }

    image.gif


    相关实践学习
    基于Redis实现在线游戏积分排行榜
    本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
    云数据库 Redis 版使用教程
    云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
    目录
    相关文章
    |
    2月前
    |
    Java API PHP
    阿里巴巴参数获取API
    阿里巴巴的参数获取API流程包括:1. 注册并认证开发者账号;2. 创建应用,获取API密钥;3. 阅读API文档,了解请求参数和返回格式;4. 编写代码调用API,如使用Python请求商品详情;5. 注意API类型及其参数,遵守数据使用规则和法律法规。
    |
    22天前
    |
    人工智能 自然语言处理 API
    Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
    谷歌推出的Multimodal Live API是一个支持多模态交互、低延迟实时互动的AI接口,能够处理文本、音频和视频输入,提供自然流畅的对话体验,适用于多种应用场景。
    69 3
    Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
    |
    10天前
    |
    JSON 安全 API
    淘宝商品详情API接口(item get pro接口概述)
    淘宝商品详情API接口旨在帮助开发者获取淘宝商品的详细信息,包括商品标题、描述、价格、库存、销量、评价等。这些信息对于电商企业而言具有极高的价值,可用于商品信息展示、市场分析、价格比较等多种应用场景。
    |
    18天前
    |
    JSON 自然语言处理 Java
    OpenAI API深度解析:参数、Token、计费与多种调用方式
    随着人工智能技术的飞速发展,OpenAI API已成为许多开发者和企业的得力助手。本文将深入探讨OpenAI API的参数、Token、计费方式,以及如何通过Rest API(以Postman为例)、Java API调用、工具调用等方式实现与OpenAI的交互,并特别关注调用具有视觉功能的GPT-4o使用本地图片的功能。此外,本文还将介绍JSON模式、可重现输出的seed机制、使用代码统计Token数量、开发控制台循环聊天,以及基于最大Token数量的消息列表限制和会话长度管理的控制台循环聊天。
    117 7
    |
    18天前
    |
    前端开发 API 数据库
    Next 编写接口api
    Next 编写接口api
    |
    24天前
    |
    XML JSON 缓存
    阿里巴巴商品详情数据接口(alibaba.item_get) 丨阿里巴巴 API 实时接口指南
    阿里巴巴商品详情数据接口(alibaba.item_get)允许商家通过API获取商品的详细信息,包括标题、描述、价格、销量、评价等。主要参数为商品ID(num_iid),支持多种返回数据格式,如json、xml等,便于开发者根据需求选择。使用前需注册并获得App Key与App Secret,注意遵守使用规范。
    |
    23天前
    |
    JSON API 开发者
    淘宝买家秀数据接口(taobao.item_review_show)丨淘宝 API 实时接口指南
    淘宝买家秀数据接口(taobao.item_review_show)可获取买家上传的图片、视频、评论等“买家秀”内容,为潜在买家提供真实参考,帮助商家优化产品和营销策略。使用前需注册开发者账号,构建请求URL并发送GET请求,解析响应数据。调用时需遵守平台规定,保护用户隐私,确保内容真实性。
    |
    23天前
    |
    搜索推荐 数据挖掘 API
    淘宝天猫商品评论数据接口丨淘宝 API 实时接口指南
    淘宝天猫商品评论数据接口(Taobao.item_review)提供全面的评论信息,包括文字、图片、视频评论、评分、追评等,支持实时更新和高效筛选。用户可基于此接口进行数据分析,支持情感分析、用户画像构建等,同时确保数据使用的合规性和安全性。使用步骤包括注册开发者账号、创建应用获取 API 密钥、发送 API 请求并解析返回数据。适用于电商商家、市场分析人员和消费者。
    |
    1月前
    |
    JSON API 开发工具
    淘宝实时 API 接口丨淘宝商品详情接口(Taobao.item_get)
    淘宝商品详情接口(Taobao.item_get)允许开发者获取商品的详细信息,包括基本信息、描述、卖家资料、图片、属性及销售情况等。开发者需注册账号、创建应用并获取API密钥,通过构建请求获取JSON格式数据,注意遵守平台规则,合理使用接口,确保数据准确性和时效性。
    |
    1月前
    |
    JSON 安全 API
    Python调用API接口的方法
    Python调用API接口的方法
    191 5