最稳定方式是用全局中间件拦截所有HTTP请求:在app/middleware/RequestCounterMiddleware.php中判断非CLI、非Ajax、非OPTIONS请求后,按GET/POST分键用cache递增计数,注册至app/middleware.php,并确保缓存驱动为Redis以防多进程不一致。

ThinkPHP 6 如何在中间件中统计所有请求次数
直接改框架入口或控制器不现实,最稳定的方式是用全局中间件拦截所有 HTTP 请求。TP6 的 AppInit 或 BeforeRequest 中间件都能拿到 $request 对象,从中可判断 $request->method() 是 GET 还是 POST。
注意:不能只监听 index.php 入口——TP6 默认使用 public/index.php,且 CLI 请求(如命令行执行)也会走中间件,需主动过滤;另外,静态资源(.js、.css、.png)通常由 Web 服务器直接处理,不会进 TP 路由,所以不会被统计到。
- 推荐在
app/middleware.php中注册一个自定义中间件,例如RequestCounterMiddleware - 计数存储建议用
cache(如file或redis),避免写文件锁或数据库压力 - 务必加
if (!$request->isAjax() && !$request->isCli())排除干扰请求
完整中间件代码(支持 GET/POST 分开计数)
在 app/middleware/RequestCounterMiddleware.php 中写:
<?php namespace app\middleware;
use think\Request;
use think\Response;
class RequestCounterMiddleware
{
public function handle(Request $request, \Closure $next): Response
{
// 只统计非 CLI、非 Ajax、非预检请求(OPTIONS)
if ($request->isCli() || $request->isAjax() || $request->method() === 'OPTIONS') {
return $next($request);
}
$method = strtoupper($request->method());
if (!in_array($method, ['GET', 'POST'])) {
return $next($request);
}
// 使用 cache 存储,key 区分方法
$key = 'request_count_' . $method;
$count = cache($key, 0) + 1;
cache($key, $count, 0); // 永不过期
return $next($request);
}
}
然后在 app/middleware.php 中注册:
return [
\app\middleware\RequestCounterMiddleware::class,
];
如何读取当前 GET 和 POST 请求总数
在控制器或命令行里直接读缓存即可,不需要额外模型或服务:
// 获取当前 GET 总数
$getCount = cache('request_count_GET', 0);
// 获取当前 POST 总数
$postCount = cache('request_count_POST', 0);
如果用了 Redis 缓存,这个值是跨进程共享的;如果是 file 缓存,在多 Worker 场景(如 Swoole)下可能不准,因为 file 缓存默认不跨进程同步——这时必须切到 redis 驱动,并确认 config/cache.php 中 default 已设为 redis。
- 检查缓存驱动:
config/cache.php的default值是否为redis - Redis 连接失败时,
cache()会静默降级为null,导致计数始终为 0 —— 建议加个简单探测:cache('test', 1); dd(cache('test')); - 不要在
handle()里做耗时操作(如数据库写入),否则拖慢所有请求
为什么不用日志或数据库记录?
日志(think\Log)写磁盘太慢,高并发下容易阻塞;数据库写入更重,还涉及连接池和事务,完全没必要为纯计数引入 I/O 瓶颈。
另一个常见错误是把计数逻辑放在 BaseController 的 initialize() 里——这只能覆盖控制器层请求,漏掉中间件提前终止(如权限拒绝)、或者未匹配路由的 404 请求。只有全局中间件能确保“只要进入 TP 生命周期,就必经一次”。
缓存 key 名称带 request_count_ 前缀是为了避免和其他业务缓存冲突;如果你的应用本身已用 Redis,且 key 空间管理严格,可以加项目前缀,比如 myapp:request_count_GET。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











