1) { $path = rtrim($path, '/'); } $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; // 开发辅助:静态资源(/assets/*)直接服务。 // 生产环境由 Web 服务器完成(Caddy/ Apache 的"真实文件直接返回"语义)。 // 仅限 public/assets 目录内,realpath 校验防路径穿越;URL 不映射业务物理路径。 if (str_starts_with($path, '/assets/')) { $assetFile = APP_ROOT . '/public' . $path; $real = realpath($assetFile); $assetRoot = realpath(APP_ROOT . '/public/assets'); if ($real !== false && $assetRoot !== false && str_starts_with($real, $assetRoot)) { // 常见类型映射(Windows fileinfo 对 css 等识别不稳定) $ext = strtolower(pathinfo($real, PATHINFO_EXTENSION)); $mimeMap = [ 'css' => 'text/css', 'js' => 'application/javascript', 'json' => 'application/json', 'png' => 'image/png', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif', 'svg' => 'image/svg+xml', 'webp' => 'image/webp', 'ico' => 'image/x-icon', 'woff' => 'font/woff', 'woff2' => 'font/woff2', ]; $mime = $mimeMap[$ext] ?? (function_exists('mime_content_type') ? mime_content_type($real) : false) ?: 'application/octet-stream'; header('Content-Type: ' . $mime); readfile($real); exit; } } Logger::info('request', ['method' => $method, 'path' => $path]); // 注册路由:先根路由表,再挂载业务模块(子空间 /) $router = new Router(); foreach ((array) require APP_ROOT . '/app/config/routes.php' as $route) { $router->add($route['method'], $route['pattern'], $route['handler'], $route['middleware'] ?? []); } (new ModuleLoader())->load($router); $match = $router->match($path, $method); if ($match === null) { Logger::warning('route not found', ['method' => $method, 'path' => $path]); Response::html( '404' . '' . '

404

页面不存在。

', 404 ); } // 执行路由中间件(拒绝时中间件自行终止响应) Middleware::run($match['middleware'], $match['params']); call_user_func($match['handler'], $match['params']); } catch (\Throwable $e) { Logger::error('uncaught exception', [ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ]); $detail = Config::get('app.debug', false) ? '
' . e($e->getMessage()) . PHP_EOL . e($e->getFile() . ':' . $e->getLine()) . '
' : '

服务器开小差了,请稍后再试。

'; Response::html( '500' . '' . '

500

' . $detail . '', 500 ); }