// +---------------------------------------------------------------------- declare(strict_types=1); namespace ywxapp\middleware; use think\facade\Config; use ywxapp\service\AddonPerformanceMonitor; /** * 插件性能监控中间件(全局注册于 app/middleware.php) * * 设计要点: * - 从请求路径首段解析插件名(插件路由统一为 /<插件名>//...), * 仅对「已启用插件」的请求做性能采样,核心应用(admin/index/api 等)零开销; * - 用 AddonPerformanceMonitor::measure() 包裹 $next($request),把每次插件 * HTTP 请求的真实耗时/内存/成功失败写入缓存,使 addon:health 的性能项有真数据; * - measure() 的 finally 已防御性吞掉缓存异常,本中间件无需再包 try/catch, * 且绝不二次调用 $next(避免重复执行业务); * - 控制器抛异常时 measure() 记录为失败并原样向外抛出,框架错误处理不受影响。 * * @author ywxapp */ class AddonPerformanceMiddleware { public function handle($request, \Closure $next) { $addon = $this->resolveAddon($request); if ($addon === null) { return $next($request); } $action = $this->resolveAction($request); return AddonPerformanceMonitor::measure($addon, $action, function () use ($next, $request) { return $next($request); }); } /** * 从路径首段解析插件名,并确认其为已启用插件(Config::get('addon') 仅含 state=1) */ private function resolveAddon($request): ?string { $path = trim((string) $request->pathinfo(), '/'); if ($path === '') { return null; } $segments = explode('/', $path); $maybe = $segments[0]; $addon = Config::get('addon', []); foreach ($addon as $info) { if (($info['name'] ?? '') === $maybe) { return $maybe; } } return null; } /** * 动作标签:HTTP 方法 + 插件名之后的剩余路径(如 GET backend/addonreview/index) */ private function resolveAction($request): string { $path = trim((string) $request->pathinfo(), '/'); $segments = explode('/', $path); array_shift($segments); // 去掉插件名首段 $rest = implode('/', $segments); return ($request->method() ?? 'GET') . ' ' . ($rest === '' ? 'index' : $rest); } }