thinkphp多应用模式下请求统计必须通过全局中间件实现,因各应用route.php仅声明路由不执行逻辑;应使用app()->name()获取真实应用名,在handle()中用cache::increment统计,避免url解析或数据库操作。

ThinkPHP多应用模式本身不提供内置的请求统计功能,必须自行实现;所有应用共享同一套中间件和日志系统,但每个应用的路由、控制器、命名空间相互隔离,统计逻辑必须在统一入口或中间件中聚合,不能靠单个应用内部埋点。
为什么不能在各应用 route.php 里分别统计
每个应用的 route.php 是独立加载的,Route::import('admin', 'admin') 只把规则导入全局路由表,并不触发执行;你放在 app/admin/route.php 里的统计代码(比如记录访问时间)根本不会被执行——框架只读取其中的 Route::get()、Route::middleware() 等声明,不执行任意 PHP 逻辑。
- 试图在
app/admin/route.php开头写file_put_contents(...),它永远不会运行 -
app/api/route.php和app/web/route.php之间无调用关系,无法互相感知请求 - 即使加了中间件,也得确保它被所有应用的路由实际使用,否则漏统
必须用全局中间件 + 请求上下文识别应用名
唯一可靠的方式是注册一个全局中间件,在每次请求开始时识别当前激活的应用名,再写入统计。关键点在于:\think\App::name() 或 request()->app() 才是真实生效的应用名,它由入口绑定(\think\App::bind())或 PATH_INFO 解析决定,不是从 URL 路径字符串里手动截取的。
- 在
app/middleware.php中注册中间件:[\app\middleware\RequestStats::class] - 中间件内不要依赖
$_SERVER['REQUEST_URI']去 parse 应用名,而要用app('http')->getName()或app()->name() - 避免在
__construct()中初始化统计资源,因为中间件实例可能复用;统计逻辑必须放在handle()内 - 若用 Redis 计数,key 建议为
stats:app:{app_name}:date:{Y-m-d},避免不同应用写冲突
完整可运行的 RequestStats 中间件源码
以下代码可直接放入 app/middleware/RequestStats.php,无需额外配置(前提是已启用多应用且正确绑定):
<?php namespace app\middleware;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Request;
class RequestStats
{
public function handle($request, \Closure $next)
{
// 获取当前实际生效的应用名(非 URL 截取)
$appName = app()->name() ?: 'index';
// 统计维度:应用名 + 日期 + 请求方法
$date = date('Y-m-d');
$method = strtolower($request->method());
$key = "stats:app:{$appName}:date:{$date}:method:{$method}";
// 原子自增(Redis 或 file cache 都支持 increment)
Cache::increment($key, 1);
// 可选:记录到日志便于调试(生产环境建议关闭)
Log::info("Request stats", [
'app' => $appName,
'method' => $method,
'uri' => $request->url(),
'ip' => $request->ip(),
]);
return $next($request);
}
}
- 该中间件对所有应用生效,包括未显式
bind()的默认应用 -
Cache::increment()自动适配当前缓存驱动(File/Redis/Memcache),无需改代码 - 若需按控制器/操作统计,可用
$request->controller()和$request->action(),但注意它们在未匹配路由时可能为空 - 不要在中间件里查数据库做统计,会拖慢所有请求;缓存 + 后台定时汇总才是正解
统计结果怎么查?别硬编码 SQL
统计数据存在缓存里,查的时候别写死 Redis CLI 或数据库查询,应封装成命令行指令,方便运维调用:
php think stats:app --date=2026-08-16 php think stats:app --app=admin --method=post
- 命令类放在
app/command/StatsApp.php,用Cache::get()批量匹配 key(如stats:app:*:date:2026-08-16*) - 避免用
Cache::tag(),多应用下 tag 隔离不严格,易串数据 - 如果用文件缓存,注意
runtime/cache/下的文件权限,确保 Web 进程和 CLI 进程都能读写
最常被忽略的是:统计中间件必须在所有应用路由加载前注册,且不能被某个应用的中间件配置覆盖;一旦漏掉 app()->name() 的调用时机,就只能拿到 index ——哪怕用户访问的是 /admin/login。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











