接口调用频次统计应采用“内存暂存+定时落盘”方案:用redis的incr+expire实现滑动窗口计数,键格式为"api:count:{md5(uri)}:{ymdhi}",10分钟过期;通过thinkphp中间件统一埋点,过滤健康检查与非http场景,设备指纹+登录态结合标识用户,时间对齐依赖日志打点。

接口调用频次统计该存哪?别直接写数据库
高频接口(比如登录、短信发送)如果每次请求都 INSERT INTO access_log,数据库会先扛不住。真正可行的路径是「内存暂存 + 定时落盘」:用 Redis 的 INCR + EXPIRE 做滑动窗口计数,再由后台任务按需同步到 MySQL 归档表。
- Redis 键建议格式:
"api:count:{md5($_SERVER['REQUEST_URI'])}:{date('YmdHi')}"(按分钟粒度,避免 key 过多) - 必须配
EXPIRE,否则内存涨满;10 分钟过期足够覆盖多数统计窗口 - 不要用
GETSET替代INCR+EXPIRE,前者无法保证原子性,高并发下计数会丢
怎么在 ThinkPHP 中无侵入地埋点?用中间件比控制器里写更稳
在每个接口方法开头手动加 $this->recordAccess(),漏一个就断一环。ThinkPHP 6+ 的中间件机制才是正解:定义一个 AccessLogMiddleware,注册到全局或路由分组,所有匹配请求自动触发。
- 中间件中获取真实接口路径用:
app('request')->url(true),不是__URL__或input() - 注意过滤健康检查类接口(如
/api/health),避免噪声干扰统计基数 - 若用了多级子域名或 API 版本前缀(如
v1/user/info),建议统一截取到user/info再计数,否则同接口因路径写法不同被算成多个
统计结果不准?检查是否漏了跨域、重定向和 CLI 调用场景
前端发请求带 Origin 头、Nginx 配了 try_files 重写、或者运维用 curl -X POST 跑脚本——这些都会绕过你写的中间件逻辑,导致数据偏低。
- CORS 预检请求(
OPTIONS)不会进中间件,但实际业务接口会进;无需统计预检,但要确认中间件没拦截掉它 - CLI 模式下调用接口(如定时任务触发支付回调)默认不走 HTTP 中间件,得单独用
think\facade\Cache::inc()补录 - Nginx 的
rewrite或return 301会直接响应,根本不到 PHP 层——这类流量只能从 access.log 解析,不在 PHP 统计范围内
Redis 计数器怎么跟用户身份挂钩?别硬塞 session_id
单纯按 IP 或 session_id 统计,会把公司内网用户全算成一个人;用 JWT 里的 uid 又可能被伪造。折中方案是「设备指纹 + 登录态兜底」:未登录时用 $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR'] 做简易指纹;已登录则优先取 think\facade\Auth::id()。
- 设备指纹要
md5()后再当 key,避免 Redis key 含特殊字符或过长 - JWT 场景下,别在中间件里反复解析 token,用
think\facade\Jwt::parse()一次取uid即可 - 注意移动端 WebView 和小程序可能禁用 cookie,
session_id不稳定,此时指纹比 session 更可靠
最麻烦的其实是时间对齐:Redis 过期时间和后台归档任务的执行时间差几秒,就可能导致同一分钟的计数被拆到两条记录里。这个得靠日志打点对齐,没法靠代码完全规避。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











