PHP路由匹配失败因$_SERVER[‘REQUEST_URI’]含子目录前缀,需用dirname($_SERVER[‘SCRIPT_NAME’])剥离;捕获组为空常因未trim()和rtrim(‘/’, $uri)统一路径;header跳转报错因输出已发送。
PHP 路由匹配失败时,$_SERVER['REQUEST_URI'] 为什么总带前缀?
常见现象是:你写了 ^/user/(\d+)$,但实际 $_SERVER['REQUEST_URI'] 是 /myapp/user/123,导致正则永远不匹配。这不是路由引擎 bug,而是 PHP 运行在子目录(如 /myapp/)下,而你没剥离上下文路径。
解决方法不是改正则,而是先标准化 URI:
- 用
preg_replace剥离$_SERVER['SCRIPT_NAME']的目录部分,例如:$uri = $_SERVER['REQUEST_URI']; $script = $_SERVER['SCRIPT_NAME']; $base = dirname($script); if ($base !== '/') { $uri = preg_replace('#^' . preg_quote($base, '#') . '#', '', $uri); } $uri = parse_url($uri, PHP_URL_PATH); // 确保只留路径 - Apache 用户可加
RewriteBase /myapp配合.htaccess,但 PHP 层仍建议主动处理,避免环境依赖 - Nginx 用户注意
fastcgi_param SCRIPT_NAME是否被覆盖,常见错误是漏写fastcgi_param SCRIPT_NAME $fastcgi_script_name;
用 preg_match 做路由匹配时,为什么捕获组全为空?
典型错误是忘记加 PREG_OFFSET_CAPTURE 以外的标志,或正则本身没启用全局/多行模式——但其实最常踩坑的是:没对 $uri 做 trim() 和尾部斜杠归一化。
比如请求 /user/123/,你的规则 ^/user/(\d+)$ 就会失败。