thinkphp6接口防刷限流失效主因是缓存驱动未切redis、限流key缺乏唯一标识、非原子操作及session丢失。需改用redis驱动,key含ip与动作,inc()原子累加,前端fetch带credentials,验证码校验前置并双维度限频。

ThinkPHP6 接口防刷限流失效,通常不是“代码没写”,而是关键环节被绕过或配置未生效。核心问题集中在缓存驱动、键设计、原子操作和请求上下文四个层面。
Cache::tag() 限流为啥完全没反应
默认文件驱动在并发下根本不可用:get() 和 set() 非原子,同一秒内多个请求读到相同旧值,计数直接漏判。这不是逻辑错,是底层机制不支持。
- 先确认缓存驱动已切到 Redis:检查 config/cache.php 中
'default' => 'redis',且'redis'配置块存在、能连通 - 限流 key 必须带唯一标识:用
'rate_limit_' . $request->ip() . '_' . $action,不能只用接口名 - 必须用
$cache->inc($key)替代手动 get+set;文件驱动不支持 inc(),会静默降级,得提前验证 -
inc()首次返回 1,判断条件应为if ($count > $limit),不是>=
验证码总校验失败,不是图的问题
captcha() 依赖 session 存原文,但接口常被 fetch 调用,默认不带 cookie,session 就断了——图生成了,但后端根本没存住验证码。
- 前端 fetch 必须加
{ credentials: 'include' };Axios 要设withCredentials: true - 后端生成验证码前,确保 session 已启动(TP6 默认开启,但 CLI 或命令行调用会失效)
- 校验时显式传
$id,如'login_' . $request->ip(),避免并发时混用默认 id - 验证码获取接口本身也要限流,比如每 IP 每 5 分钟最多一次,防止被批量拉取
IP 限流误伤办公网用户
单靠 IP 限流,在校园网、企业出口等 NAT 场景下极易封错人。得用分层响应,而不是一刀切。
- 第一层:对
/api/login这类敏感接口,查 IP 最近 1 分钟请求数,超 5 次直接返回 429,不给验证码机会 - 第二层:未超阈值但 UA 异常(如为空、含
python-requests),强制要求提交验证码字段,否则拒绝 - 第三层:验证码连续失败 3 次,用
Cache::set('block_' . $ip, 1, 900)锁定该 IP 15 分钟 - 所有限流 key 建议加时间分片,如
'req_' . date('i') . '_' . $ip,避免单 key 过热影响 Redis 性能
短信接口还在被刷?说明防刷链路断了
仅前端倒计时、仅 IP 限频、甚至只做手机号维度限频,都挡不住真实攻击。攻击者直击接口地址,完全跳过页面逻辑。
- 图形验证码校验必须在短信发送逻辑之前执行,三步闭环:生成 → 提交 → 校验,缺一不可
- 限频必须双维度:IP + 手机号,key 如
'sms_limit_' . $ip . '_' . $phone - 验证码校验通过后,才允许进入短信发送流程;否则直接返回错误,不调第三方 SDK
- 注意缓存清理时机:验证码校验成功后,立即删掉对应 key,防止重放
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











