要准确统计请求频次,需在中间件中主动用Cache::inc()递增计数并设60秒TTL,标准化route(去query、统一大写),导出数据时单点查询避免KEYS阻塞,返回前强制(int)转换count字段确保ECharts正确渲染。

ThinkPHP 6 的 throttle 中间件怎么用才不漏统计?
默认的 throttle 中间件只做拦截,不记录原始请求频次——你看到“429 Too Many Requests”,但查不到用户过去1分钟到底发了多少次。要统计,得自己接管计数逻辑。
推荐在中间件里手动调用缓存递增,而不是依赖 throttle 的内置判断:
- 用
Cache::inc('api:rate:'.$ip.':'.$route, 1)主动累加,比读-改-写更原子 - 配合
Cache::set($key, 0, 60)初始化(仅首次),避免空值导致递增失败 - 注意
$route要标准化:去掉 query 参数、统一大小写,否则/user?id=1和/user?id=2会被算作不同接口
如何把限流数据导出成 JSON 供 ECharts 渲染?
别直接查 Redis keys——KEYS api:rate:* 在生产环境会阻塞主线程。应该用前缀扫描 + 分页拉取:
- 用
Cache::get('api:rate:'.$ip.':'.$route)单点查,配合前端传来的ip和route查询条件 - 后台接口返回结构示例:
{"data":[{"ip":"192.168.1.100","route":"/api/v1/order","count":17,"expire":53}]} - 前端用
setInterval每30秒轮询一次,避免 WebSocket 增加部署复杂度
Redis 缓存键设计不当会导致统计错乱?
常见错误是把时间窗口硬编码进 key,比如 api:rate:20240520:192.168.1.100——这会让每小时/每天生成新 key,无法滚动统计最近60秒。
立即学习“PHP免费学习笔记(深入)”;
- 正确做法:key 不含时间戳,靠缓存 TTL 控制生命周期,例如
Cache::set($key, $count, 60) - 如果需要多维度(如按用户ID+IP+接口),用冒号拼接但保持层级清晰:
api:rate:user_123:192.168.1.100:/order - 特别注意:Redis 的
INCR对不存在的 key 默认设为 1,所以首次调用Cache::inc()就能自动初始化,无需先set(0)
为什么 ECharts 折线图总显示“无数据”?
大概率是后端返回的 count 字段是字符串类型(Redis 返回的都是 string),而 ECharts 的 series.data 要求数值数组。
- 前端必须显式转换:
data: res.data.map(d => Number(d.count)) - 后端接口建议统一 cast:
'count' => (int) $value,避免 PHP 自动类型转换在某些版本下行为不一致 - 测试时用
curl -v http://your.app/api/rate?ip=192.168.1.100直接看原始响应,比在浏览器里调试更快
真正难的不是画图,而是确保每一行数据都来自同一时间粒度、同一聚合口径。比如你用 60 秒 TTL,但前端每 10 秒拉一次,又没做服务端去重,图表就会抖动。这种细节,文档里通常不提。



















