引言
接口防刷是生产项目落地必须解决的问题,这篇文章会从架构的角度,分层次的讲讲如何解决这个问题。
接口防刷(rate limiting / anti-scraping)的核心在于“识别请求”和“限制频率”

第一层:客户端/前端层 (client side)
在client层我们并不能阻止真正的攻击者,属于“防君子不防小人”,主要目的是增加作弊成本,而不是彻底阻断。
下面是在这一层常见的措施。
ui 交互限制
- 按钮置灰:点击发送后,按钮强制置灰几秒钟(防止用户手抖重复提交)。
图形/行为验证码 (captcha)
- 在敏感接口(注册、登录、领券)引入滑块、点击选字或 google recaptcha。
- 逻辑:只有验证码校验通过,才颁发一个临时的 token,后端接口校验该 token。
参数签名 (signature) & 防重放
- 机制:客户端使用 ak/sk 对请求参数 + 时间戳 + 随机数 (nonce) 进行签名。
- 作用:防止抓包篡改参数。
- 防重放:后端校验时间戳(例如只允许 60s 内的请求),并缓存 nonce(60s 内不能重复)。
第二层:网络/网关接入层 (network / gateway)
在这一层我们一定要挡住绝大部分的异常流量,保护后端服务不被压垮。
- waf (web application firewall)
- 如果公司有预算,直接上对应云服务厂商(比如阿里云/aws) 的 waf 或者 cloudflare。它们能基于指纹库识别恶意爬虫、bot 流量,直接在边缘节点阻断。
2.nginx 反向代理层
ip 限流 (
limit_req_zone) :这是最基础的。# 定义限流空间,以 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 段。
- api 网关 (gateway)
技术栈:spring cloud gateway/zuul,kong, apisix, tyk,higress。
策略:
- 身份鉴权:在网关层校验 token (jwt),无效请求直接丢弃,不透传给后端。
- 全局流控:基于令牌桶(token bucket)或漏桶(leaky bucket)算法,限制整个服务的 qps 上限。
第三层:应用/服务层 (application / middleware)
这里就是业务层来阻断的地方了,可以针对某个业务进行更加精细的限流操作。
- 业务维度的限流 (redis + lua)
场景:限制某个用户 (user_id) 在特定时间窗口内只能调用 n 次。
为什么用 lua? 保证 redis 操作(读+写)的原子性。
滑动窗口算法:比固定窗口更平滑,防止“临界点突发”问题。
- 示例逻辑:使用 redis
zset。key 是user_id:action,score 是时间戳。每次请求移除窗口外的数据,统计窗口内的数量。
- 示例逻辑:使用 redis
- 单机/集群限流组件
java 生态:
- guava ratelimiter:单机限流,基于令牌桶,适合非集群环境。
- alibaba sentinel:神器。支持单机、集群、热点参数限流(例如:防止某个热点商品 id 被刷),支持降级熔断。
go 生态:
golang.org/x/time/rate:官方标准库,基于令牌桶。- uber-go/ratelimit:基于漏桶模型,更注重请求的均匀性。
- 幂等性设计 (idempotency)
- 防止因为网络抖动或脚本重试导致的重复操作。
- 实现:客户端生成唯一的
request-id,后端在拦截器和redis中检查该 id 是否已处理过。
如果面对脚本,我们在这一层一般有什么解决方法呢?
动态风控/黑名单
- 分析用户行为模型。如果一个用户 24 小时都在请求接口,或者只抢红包不看页面,标记为灰名单/黑名单。
- java/go 处理:在 filter/middleware 中,检查用户 id 是否在 redis 的黑名单 set 中,如果在,直接返回 403。
人机验证升级
- 当系统检测到某用户频率稍高但不确定是否为攻击时,不直接封禁,而是弹出验证码。
- 只有通过验证码,才允许继续操作。
第四层:数据持久层 (database)
最后的兜底,防止数据错乱。
数据库唯一索引 (unique index)
- 例如:防止用户重复领取优惠券,在
coupon_record表对user_id+campaign_id建唯一索引。
- 例如:防止用户重复领取优惠券,在
悲观锁/乐观锁
- 乐观锁:
update account set balance = balance - 100, version = version + 1 where id = 1 and version = old_version。防止并发扣减刷成负数。
- 乐观锁:
总结
到此这篇关于一站式了解接口防刷(限流)的基本操作的文章就介绍到这了,更多相关接口防刷内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论