BLOG

轻量PHP路由器如何处理参数和404页面

小型CMS也需要清楚的路由匹配、参数提取和统一404处理。

分类:PHP 全栈开发 阅读:210
轻量PHP路由器如何处理参数和404页面
轻量PHP路由器如何处理参数和404页面

小型CMS不一定需要复杂框架,但仍需要一层清楚的路由处理。它负责把请求方法和网址路径匹配到对应处理器,提取路径参数,并在没有规则命中时返回真正的404。路由器的职责应保持有限:识别请求、校验参数形状、分发处理器;权限判断和具体业务操作留给后续层处理。

先把请求路径整理干净

PHP可以从 $_SERVER['REQUEST_URI'] 取得请求地址,但其中可能包含查询字符串。用于路由匹配的应是路径部分,可以通过 parse_url() 提取。路径为空时统一视为根路径,并处理末尾斜杠规则,避免同一页面同时出现多套地址。

```php
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$path = parse_url($uri, PHP_URL_PATH) ?: '/';
$path = rawurldecode($path);

if ($path !== '/') {
$path = rtrim($path, '/');
}
```

是否保留末尾斜杠需要在站点中统一。可以选择重定向到规范地址,也可以在匹配前统一去掉,但不要让 /blog/a 和 /blog/a/ 返回两份可收录内容。rawurldecode() 之后仍要把参数当作外部输入处理,不能因为路由匹配成功就直接信任。

静态路由与参数路由分开理解

静态路由是完整路径匹配,例如 /about。参数路由则包含变化部分,例如 /blog/{slug}。轻量实现可以把占位符转换为命名正则组,并在匹配后读取参数。规则本身要限制参数可接受的字符,数字ID与文章slug不应共用宽泛的 .*。

```php
$routes = [
['GET', '#^/blog/(?P<slug>[a-z0-9-]+)$#', 'showArticle'],
['GET', '#^/works/(?P<id>\d+)$#', 'showWork'],
];

foreach ($routes as [$allowedMethod, $pattern, $handler]) {
if ($method !== $allowedMethod) {
continue;
}
if (preg_match($pattern, $path, $matches) !== 1) {
continue;
}

$params = array_filter(
$matches,
static fn ($key) => is_string($key),
ARRAY_FILTER_USE_KEY
);
$handler($params);
return;
}
```

参数进入处理器后仍需按业务再次校验。正则只能确认基本形状,不能证明记录存在,也不能证明当前用户有权查看。文章slug需要查询状态与发布时间,资源ID需要检查权限,后台操作还要验证登录身份和请求令牌。

路径不存在与方法不允许不是一回事

同一个路径可能存在GET页面,但不接受POST。如果只按“方法加路径”查找,POST未命中后直接返回404,会掩盖真实问题。简单路由器可以先判断是否存在任何方法的相同路径:路径存在但方法不支持时返回405,并通过 Allow 响应头说明允许的方法;路径本身不存在才返回404。

对于只服务网页的小型站点,也可以保持实现简洁,但日志里应区分这两类情况。这样排查表单提交错误时,不会误以为页面地址不存在。

404必须同时处理状态和页面

未匹配请求不能只渲染“页面不存在”的文字,还要发送HTTP 404状态码。否则浏览器看起来像404,搜索引擎和监控工具却可能收到200,这类情况常被称为软404。

```php
http_response_code(404);
header('Content-Type: text/html; charset=utf-8');
require __DIR__ . '/../views/errors/404.php';
```

404页面应保留站点名称、返回首页或搜索入口,但不要把所有错误地址重定向到首页。重定向会让访问者不清楚原地址已经失效,也不利于识别站内坏链接。若文章确实迁移到新地址,才使用指向对应新页面的永久重定向。

防止路由器暴露内部细节

路由错误不应把文件绝对路径、查询语句或异常堆栈显示给访客。生产环境返回统一错误页,详细原因写入受保护日志。日志可以记录请求方法、规范化路径、匹配结果和请求标识,但不要记录密码、令牌或完整敏感参数。

路由目标也不能直接来自用户输入。例如把URL中的控制器名拼接成文件路径,会带来路径穿越和任意文件加载风险。允许的处理器应来自程序内部定义的映射表。

用一组边界请求验证

上线前至少覆盖根路径、正常静态页、合法参数、非法参数、记录不存在、末尾斜杠、带查询字符串、错误请求方法和完全未知路径。检查的不只是页面文字,还包括状态码、规范链接、日志内容以及受限页面是否仍经过权限判断。

轻量路由器的价值不在代码行数少,而在行为容易预期。路径规则集中、参数边界清楚、404状态正确,后续新增文章、作品和后台页面时才能继续维护,而不会让每个入口各自解释网址。

评论

登录后可发表评论。