一站式了解接口防刷(限流)的基本操作

引言

接口防刷是生产项目落地必须解决的问题,这篇文章会从架构的角度,分层次的讲讲如何解决这个问题。

接口防刷(Rate Limiting / Anti-scraping)的核心在于"识别请求"和"限制频率"

第一层:客户端/前端层 (Client Side)

在client层我们并不能阻止真正的攻击者,属于"防君子不防小人",主要目的是增加作弊成本,而不是彻底阻断。

下面是在这一层常见的措施。

  • UI 交互限制

    • 按钮置灰:点击发送后,按钮强制置灰几秒钟(防止用户手抖重复提交)。
  • 图形/行为验证码 (CAPTCHA)

    • 在敏感接口(注册、登录、领券)引入滑块、点击选字或 Google ReCaptcha。
    • 逻辑:只有验证码校验通过,才颁发一个临时的 Token,后端接口校验该 Token。
  • 参数签名 (Signature) & 防重放

    • 机制:客户端使用 AK/SK 对请求参数 + 时间戳 + 随机数 (Nonce) 进行签名。
    • 作用:防止抓包篡改参数。
    • 防重放:后端校验时间戳(例如只允许 60s 内的请求),并缓存 Nonce(60s 内不能重复)。

第二层:网络/网关接入层 (Network / Gateway)

在这一层我们一定要挡住绝大部分的异常流量,保护后端服务不被压垮。

  1. WAF (Web Application Firewall)
  • 如果公司有预算,直接上对应云服务厂商(比如阿里云/AWS) 的 WAF 或者 Cloudflare。它们能基于指纹库识别恶意爬虫、Bot 流量,直接在边缘节点阻断。

2.Nginx 反向代理层

  • IP 限流 (limit_req_zone) :这是最基础的。

    nginx 复制代码
    # 定义限流空间,以 IP 为 key,限制每秒 10 个请求
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    
    server {
        location /api/ {
            # 应用限流,burst=5 允许瞬间突发 5 个,nodelay 立即处理
            limit_req zone=api_limit burst=5 nodelay;
        }
    }
  • 黑名单机制 :Nginx 可以直接 deny 某些恶意 IP 段。

  1. API 网关 (Gateway)
  • 技术栈 :Spring Cloud Gateway/Zuul,Kong, APISIX , Tyk,Higress

  • 策略

    • 身份鉴权:在网关层校验 Token (JWT),无效请求直接丢弃,不透传给后端。
    • 全局流控:基于令牌桶(Token Bucket)或漏桶(Leaky Bucket)算法,限制整个服务的 QPS 上限。

第三层:应用/服务层 (Application / Middleware)

这里就是业务层来阻断的地方了,可以针对某个业务进行更加精细的限流操作。

  1. 业务维度的限流 (Redis + Lua)
  • 场景 :限制某个用户 (User_ID)特定时间窗口内只能调用 N 次。

  • 为什么用 Lua? 保证 Redis 操作(读+写)的原子性。

  • 滑动窗口算法:比固定窗口更平滑,防止"临界点突发"问题。

    • 示例逻辑 :使用 Redis ZSET。Key 是 User_ID:Action,Score 是时间戳。每次请求移除窗口外的数据,统计窗口内的数量。
  1. 单机/集群限流组件
  • Java 生态

    • Guava RateLimiter:单机限流,基于令牌桶,适合非集群环境。
    • Alibaba Sentinel:神器。支持单机、集群、热点参数限流(例如:防止某个热点商品 ID 被刷),支持降级熔断。
  • Go 生态

    • golang.org/x/time/rate:官方标准库,基于令牌桶。
    • Uber-go/ratelimit:基于漏桶模型,更注重请求的均匀性。
  1. 幂等性设计 (Idempotency)
  • 防止因为网络抖动或脚本重试导致的重复操作。
  • 实现 :客户端生成唯一的 Request-ID,后端在拦截器和Redis中检查该 ID 是否已处理过。

如果面对脚本,我们在这一层一般有什么解决方法呢?

  • 动态风控/黑名单

    • 分析用户行为模型。如果一个用户 24 小时都在请求接口,或者只抢红包不看页面,标记为灰名单/黑名单
    • Java/Go 处理:在 Filter/Middleware 中,检查用户 ID 是否在 Redis 的黑名单 Set 中,如果在,直接返回 403。
  • 人机验证升级

    • 当系统检测到某用户频率稍高但不确定是否为攻击时,不直接封禁,而是弹出验证码
    • 只有通过验证码,才允许继续操作。

第四层:数据持久层 (Database)

最后的兜底,防止数据错乱。

  1. 数据库唯一索引 (Unique Index)

    • 例如:防止用户重复领取优惠券,在 coupon_record 表对 user_id + campaign_id 建唯一索引。
  2. 悲观锁/乐观锁

    • 乐观锁UPDATE account SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = old_version。防止并发扣减刷成负数。

总结

ok,这就是接口防刷(限流)的分层操作,如果有错误或者笔误、或者有更好的建议,期待在评论区提出来,谢谢!

相关推荐
裴云飞1 小时前
Compose原理九之测量布局
架构
何中应1 小时前
RabbitMQ安装及简单使用
分布式·后端·消息队列
何中应1 小时前
使用Python统计小说语言描写的字数
后端·python
张二森2 小时前
分布式存储的战争(四)AI的咆哮-GPFS/Deepseek 3FS 并行文件系统
架构
何中应2 小时前
SpringAMQP消息转化器
分布式·后端·消息队列
姜源Jerry2 小时前
【Trae】Trae IDE&SOLO浅尝
java·ide·ai
宇木灵2 小时前
C语言基础-三、流程控制语句
java·c语言·前端
小杨互联网3 小时前
项目CyberScan Pro jar软件安全成分分析插件
java·jar·软件成分分析·jar安全分析