You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC框架路由匹配异常:请求URL无法匹配正确的user路由

路由匹配异常问题

我在自己的MVC框架里定义了两条路由:

$routes["\/"] = $index;
$routes["\/user\/(\d+)"] = $user;

通过$request_url = $_SERVER["REQUEST_URI"];获取请求URL,再用以下代码做正则匹配:

$reg_ex = "/$route/i";
$matches = [];

preg_match($reg_ex, $request_url, $matches);

但出现匹配异常:当请求URL为/MVC-Framework/user/1时,只会匹配到/路由,无法匹配正确的user路由。

完整代码

$request_url = $_SERVER["REQUEST_URI"];

echo $request_url . "<br />";

$index = function(){
    echo "index route";
};

$user = function(){
    echo "user route";
};

$http_404 = function(){
    echo "error 404";
};

$routes = [];

$routes["\/"] = $index;
$routes["\/user\/(\d+)"] = $user;

foreach($routes as $route => $action){
    //$reg_ex = "/" . $route . "/";
    $reg_ex = "/$route/i";
    $matches = [];

    preg_match($reg_ex, $request_url, $matches);
    print_r($matches);

    if(!preg_match($reg_ex, $request_url, $matches)){
        continue;
    }

    if(!is_callable($action)){
        return call_user_func_array($http_404, $matches);
    }

    array_shift($matches);

    return call_user_func_array($action, $matches);
}

return call_user_func_array($http_404, [$request_url]);

输出结果

/MVC-Framework/user/42
Array ( [0] => / ) index route


问题原因及解决办法

问题根源

  1. 正则未做精确匹配:第一个路由的正则\/会匹配URL中任意位置的单个斜杠,比如请求URL开头的/,导致直接命中index路由。
  2. 循环提前终止:匹配到第一个路由后直接return,循环停止,后续的user路由根本不会被检查。
  3. URL包含项目前缀:请求URL带有项目根路径/MVC-Framework,但路由规则是基于相对路径定义的,两者不匹配。

修复步骤

1. 剥离URL中的项目前缀

先把请求URL里的项目根路径去掉,只保留路由匹配需要的相对路径:

$base_path = '/MVC-Framework';
$request_url = str_replace($base_path, '', $_SERVER["REQUEST_URI"]);
// 统一路径格式,避免末尾多斜杠的情况
$request_url = rtrim($request_url, '/') ?: '/';

2. 修改路由正则为精确匹配

给每个路由正则添加^(开头锚定)和$(结尾锚定),确保只有完全匹配的路径才会命中:

$routes["^\/$"] = $index;
$routes["^\/user\/(\d+)$"] = $user;

3. 调整循环逻辑,避免提前终止

先遍历所有路由找到匹配项,再执行对应逻辑,而不是匹配到一个就直接返回:

$matched_action = $http_404;
$matched_params = [$request_url];

foreach($routes as $route => $action){
    $reg_ex = "/$route/i";
    $matches = [];
    if(preg_match($reg_ex, $request_url, $matches)){
        if(is_callable($action)){
            $matched_action = $action;
            array_shift($matches);
            $matched_params = $matches;
            break; // 找到第一个匹配路由后退出循环
        }
    }
}

call_user_func_array($matched_action, $matched_params);

修正后的完整代码

// 剥离项目前缀
$base_path = '/MVC-Framework';
$request_url = str_replace($base_path, '', $_SERVER["REQUEST_URI"]);
$request_url = rtrim($request_url, '/') ?: '/';

echo $request_url . "<br />";

$index = function(){
    echo "index route";
};

$user = function($id){
    echo "user route, user ID: " . $id;
};

$http_404 = function($url){
    echo "error 404: " . $url;
};

$routes = [];

// 添加首尾锚定符,确保精确匹配
$routes["^\/$"] = $index;
$routes["^\/user\/(\d+)$"] = $user;

$matched_action = $http_404;
$matched_params = [$request_url];

foreach($routes as $route => $action){
    $reg_ex = "/$route/i";
    $matches = [];
    if(preg_match($reg_ex, $request_url, $matches)){
        if(is_callable($action)){
            $matched_action = $action;
            array_shift($matches);
            $matched_params = $matches;
            break;
        }
    }
}

call_user_func_array($matched_action, $matched_params);

修改后,请求/MVC-Framework/user/42会正确匹配user路由,输出user route, user ID: 42;请求/MVC-Framework/会匹配index路由。

内容的提问来源于stack exchange,提问作者coding beginner no. 133920

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:48:23