文档目录
前台路由系统

简介

本文件面向开发者,系统化说明 DouPHP 前台路由系统的工作原理、URL 匹配机制、声明式路由配置方式,以及静态路由、动态路由、RESTful 风格路由的实现方法。文档同时给出 SEO 友好的 URL 设计建议、性能优化与缓存策略,并提供灵活定制指南,帮助你在不侵入核心逻辑的前提下扩展或调整前台路由行为。

项目结构

前台路由由“入口预处理 → 规则匹配 → 解析调度 → 控制器执行”的链路组成,关键位置如下:

  • 语言前缀剥离:LangPrefixParser
  • 规则匹配:PrettyRouteMatcher(基于 RouteManifest 的前台 declared 条目)
  • 解析与装配:FrontResolver(组装中间件、参数、视图上下文等)
  • 调度执行:Router(薄壳,委托 Dispatcher)
  • 业务路由声明:front/route/*.php(如 product.php、article.php、page.php)
  • 风格规则配置:config/route.php(按风格分组定义 pattern、params、target、short_rules 等)
graph TB
A["请求进入<br/>前台入口"] --> B["LangPrefixParser<br/>剥离语言前缀"]
B --> C["PrettyRouteMatcher<br/>匹配 declared 规则"]
C --> D{"是否命中?"}
D -- "否" --> E["FrontResolver 返回 notFound<br/>渲染 page_wrong"]
D -- "是" --> F["FrontResolver<br/>组装中间件/参数/视图上下文"]
F --> G["Dispatcher::run<br/>调用控制器方法"]
G --> H["响应输出"]

图示来源

  • front/foundation/routing/LangPrefixParser.php:21-58
  • front/foundation/routing/PrettyRouteMatcher.php:44-114
  • front/foundation/routing/FrontResolver.php:43-106
  • front/foundation/routing/Router.php:26-57

章节来源

  • front/foundation/routing/LangPrefixParser.php:21-58
  • front/foundation/routing/PrettyRouteMatcher.php:44-114
  • front/foundation/routing/FrontResolver.php:43-106
  • front/foundation/routing/Router.php:26-57

核心组件

  • LangPrefixParser:在 Init 之前安全剥离多语言前缀(如 zh-cn),将语言标识与去前缀后的路由串分别写入 Request。
  • PrettyRouteMatcher:唯一外观 URL 解析来源,读取 RouteManifest 中前台命名空间的 declared 条目,使用预编译的正则进行匹配;支持短地址策略(ShortUrlPolicy)与 HTTP 方法消歧。
  • FrontResolver:将匹配结果转换为 DispatchPlan,注入中间件链、路由参数、视图变量,并加载主题扩展。
  • Router:薄壳调度器,负责调用 FrontResolver 与 Dispatcher,未命中时返回 404 提示页。
  • 业务路由声明:front/route/*.php 通过 Route::column / Route::simple / Route::page 等声明式 API 生成 declared 条目,最终被 PrettyRouteMatcher 消费。

章节来源

  • front/foundation/routing/LangPrefixParser.php:21-58
  • front/foundation/routing/PrettyRouteMatcher.php:25-114
  • front/foundation/routing/FrontResolver.php:32-106
  • front/foundation/routing/Router.php:26-57
  • front/route/product.php:15-30
  • front/route/article.php:15-30
  • front/route/page.php:15-31

架构总览

前台路由采用“纯声明式 + 预编译正则”的架构,确保入站匹配与出站 URL 构建的一致性。核心流程如下:

  • 入口预处理:LangPrefixParser 剥离语言前缀,避免污染业务路由匹配。
  • 规则匹配:PrettyRouteMatcher 从 RouteManifest 加载前台 declared 条目,统一用 PrettyUrlCompiler 编译为正则,按 specificity 排序后匹配。
  • 解析装配:FrontResolver 根据命中条目组装中间件链、路由参数、视图上下文,并加载主题扩展。
  • 调度执行:Router 委托 Dispatcher 执行控制器方法,未命中则返回 404。
sequenceDiagram
participant Client as "客户端"
participant Parser as "LangPrefixParser"
participant Matcher as "PrettyRouteMatcher"
participant Resolver as "FrontResolver"
participant Router as "Router"
participant Dispatcher as "Dispatcher"
participant Controller as "控制器"
Client->>Parser : 原始 route 串
Parser-->>Client : langSign, routeString
Client->>Matcher : normalize(routeString, method)
Matcher-->>Resolver : {module, action, sub, params, controller, ...}
Resolver->>Resolver : 组装中间件/参数/视图
Resolver-->>Router : DispatchPlan
Router->>Dispatcher : run(plan, container)
Dispatcher->>Controller : 调用具体方法
Controller-->>Client : Response

图示来源

  • front/foundation/routing/LangPrefixParser.php:31-58
  • front/foundation/routing/PrettyRouteMatcher.php:61-114
  • front/foundation/routing/FrontResolver.php:52-106
  • front/foundation/routing/Router.php:40-57

详细组件分析

语言前缀剥离:LangPrefixParser

  • 职责:在 Init 之前剥离多语言前缀(形如 zh-cn),将语言标识与去前缀路由串分别写入 Request。
  • 特点:纯函数级工具,不依赖 Config/Locale/容器,可在初始化早期安全运行。
  • 影响:后续路由匹配不再受语言前缀干扰,首页由空路由串派生。

章节来源

  • front/foundation/routing/LangPrefixParser.php:21-58

规则匹配:PrettyRouteMatcher

  • 数据来源:仅消费 RouteManifest 中前台命名空间(\Dou\Front)的 declared 条目。
  • 匹配算法:
    • 收集全部命中规则,按 specificity 排序(占位符少优先、字面段多优先、声明顺序兜底)。
    • 传入 HTTP 方法进行方法感知消歧(HEAD 按 GET 处理)。
    • 短地址策略:启用后禁止带模块前缀的长格式;若原路径未命中,尝试补回模块前缀再匹配一次,保证可逆。
  • 结果结构:包含 module、action、sub、controller、params、mw_* 等字段,供 FrontResolver 使用。
flowchart TD
Start(["normalize 入口"]) --> Trim["去除首尾斜杠"]
Trim --> Blank{"是否为空串?"}
Blank -- "是" --> Home["返回 IndexController"]
Blank -- "否" --> CheckPrefixed{"是否带模块前缀且短地址启用?"}
CheckPrefixed -- "是" --> Reject["拒绝长格式"]
CheckPrefixed -- "否" --> Match["匹配所有 declared 规则"]
Match --> AnyMatch{"有命中?"}
AnyMatch -- "否" --> ShortFallback{"短地址兜底?"}
ShortFallback -- "是" --> TryPrefixed["补回模块前缀重试"]
ShortFallback -- "否" --> NotFound["返回未命中"]
AnyMatch -- "是" --> Build["buildResult 组装标准路由信息"]
Build --> End(["返回结果"])
Reject --> End
Home --> End
NotFound --> End

图示来源

  • front/foundation/routing/PrettyRouteMatcher.php:61-114
  • front/foundation/routing/PrettyRouteMatcher.php:116-169
  • front/foundation/routing/PrettyRouteMatcher.php:254-293

章节来源

  • front/foundation/routing/PrettyRouteMatcher.php:25-114
  • front/foundation/routing/PrettyRouteMatcher.php:116-169
  • front/foundation/routing/PrettyRouteMatcher.php:254-293

解析与装配:FrontResolver

  • 职责:将匹配结果转为 DispatchPlan,设置基础 URL、路由模块/动作/子段、路由参数,合并到输入,分配视图变量,加载主题扩展。
  • 中间件链:默认栈为“安全头 → 可信代理 → 限流 → 会员认证(可选)→ CSRF”,可通过命中条目的 mw_* 字段进行路由级细化(追加、排除、参数、跳过全部)。
  • 表单目标:对 create/edit 资源动作自动装配 form_action 与 form_method,便于模板统一渲染。
classDiagram
class FrontResolver {
+resolve(request, container) DispatchPlan
-composeMiddlewares(container, result) array
-assignFormTarget(action, result, params) void
-loadThemeExtension(container, module, action) void
}
class MiddlewareRegistry {
+composeFromSpec(defaultAliases, skipAll, without, append, params) array
}
class ThemeExtensionLoader {
+loadForRoute(module, action) void
}
FrontResolver --> MiddlewareRegistry : "组装中间件链"
FrontResolver --> ThemeExtensionLoader : "加载主题扩展"

图示来源

  • front/foundation/routing/FrontResolver.php:52-106
  • front/foundation/routing/FrontResolver.php:174-199
  • front/foundation/routing/FrontResolver.php:123-157

章节来源

  • front/foundation/routing/FrontResolver.php:32-106
  • front/foundation/routing/FrontResolver.php:123-157
  • front/foundation/routing/FrontResolver.php:174-199

调度执行:Router

  • 职责:薄壳调度器,获取 Request,调用 FrontResolver 得到 DispatchPlan,未命中返回 404;命中则交由 Dispatcher 执行。
  • 特点:不直接参与匹配与解析,保持职责单一。

章节来源

  • front/foundation/routing/Router.php:26-57

业务路由声明:front/route/*.php

  • 产品栏目:product.php 使用 Route::column('product', ProductController::class),按当前 column 风格展开为多条 declared 条目(列表/分类/详情)。
  • 文章栏目:article.php 使用 Route::column('article', ArticleController::class)。
  • 单页:page.php 使用 Route::page(PageController::class),按 page 风格展开(suffix/prefixed/id 等)。

章节来源

  • front/route/product.php:15-30
  • front/route/article.php:15-30
  • front/route/page.php:15-31

依赖关系分析

  • 入口层:LangPrefixParser 解耦语言前缀,使后续匹配不受影响。
  • 匹配层:PrettyRouteMatcher 依赖 RouteManifest 与 PrettyUrlCompiler,确保入站匹配与出站构建一致。
  • 解析层:FrontResolver 依赖 MiddlewareRegistry 与 ThemeExtensionLoader,完成中间件链与主题扩展装配。
  • 调度层:Router 依赖 Dispatcher,统一执行控制器方法。
graph LR
LPP["LangPrefixParser"] --> PRM["PrettyRouteMatcher"]
PRM --> FR["FrontResolver"]
FR --> MW["MiddlewareRegistry"]
FR --> TEL["ThemeExtensionLoader"]
FR --> R["Router"]
R --> D["Dispatcher"]

图示来源

  • front/foundation/routing/LangPrefixParser.php:31-58
  • front/foundation/routing/PrettyRouteMatcher.php:324-353
  • front/foundation/routing/FrontResolver.php:174-199
  • front/foundation/routing/Router.php:40-57

章节来源

  • front/foundation/routing/PrettyRouteMatcher.php:324-353
  • front/foundation/routing/FrontResolver.php:174-199
  • front/foundation/routing/Router.php:40-57

性能与缓存策略

  • 规则预编译:PrettyRouteMatcher 在构造时加载并预编译所有前台 declared 规则的 regex,避免每次请求重复编译,降低 CPU 开销。
  • 短路匹配:首页空串直接短路返回 IndexController,减少正则匹配成本。
  • 短地址策略:启用后禁止带模块前缀的长格式,减少无效匹配分支;未命中时仅做一次补前缀重试,控制额外开销。
  • 中间件链复用:默认栈固定,路由级细化通过 mw_* 字段精确控制,避免全局中间件误伤。
  • 建议:
    • 合理组织 declared 条目顺序,将更具体的规则置于前面,提升匹配效率。
    • 谨慎使用复杂正则,尽量使用具名捕获组与明确边界。
    • 开启短地址策略时,确保 URL 生成与匹配策略一致,避免冗余分支。

故障排查指南

  • 未命中路由:
    • 检查 LangPrefixParser 是否正确剥离语言前缀。
    • 确认 PrettyRouteMatcher 是否加载了正确的 declared 条目(仅前台命名空间)。
    • 验证 pattern 与 params 正则是否与 URL 一致。
  • 方法不匹配:
    • 确认 declared 条目的 methods 字段是否限制了 HTTP 方法(如 update PUT vs destroy DELETE)。
    • HEAD 请求按 GET 处理,注意方法语义。
  • 短地址问题:
    • 启用短地址策略后,禁止使用带模块前缀的长格式;若需兼容,请确保 URL 生成器与匹配策略一致。
  • 中间件异常:
    • 通过 mw_without/mw_append/mw_params 精细控制路由级中间件;必要时使用 mw_skip_all 跳过全部默认栈。

章节来源

  • front/foundation/routing/PrettyRouteMatcher.php:61-114
  • front/foundation/routing/PrettyRouteMatcher.php:178-189
  • front/foundation/routing/FrontResolver.php:174-199

结论

DouPHP 前台路由系统以“纯声明式 + 预编译正则”为核心,结合短地址策略与方法感知消歧,提供了高效、可维护、可扩展的路由能力。通过 config/route.php 的风格化配置与 front/route/*.php 的声明式 API,开发者可以灵活定义静态路由、动态路由与 RESTful 风格路由,同时借助中间件链与主题扩展实现安全、可控的执行环境。遵循 SEO 友好的 URL 设计建议与性能优化实践,可获得更好的用户体验与系统稳定性。

附录:配置示例与实践

路由配置文件结构与定义方式

  • 位置:config/route.php
  • 结构:按风格分组(page、column、simple),每组包含 name、rules、short_rules 等字段。
  • 关键字段:
    • pattern:URL 模式,支持 {param}、{param:regex}、[/optional] 语法。
    • params:参数默认正则(pattern 内嵌正则优先)。
    • target:目标文件名模板(默认 {module}.php)。
    • module_fixed:固定模块名(用于 URL 不含模块段的情况)。
    • short_rules:短地址模块专用规则家族(仅 column 风格),顶级分类别名取代模块名段,其余结构与 rules 一致。

章节来源

  • config/route.php:15-31
  • config/route.php:32-356

静态路由、动态路由、RESTful 路由实现

  • 静态路由:通过固定 pattern(如 page/{slug}.html)映射到固定控制器方法。
  • 动态路由:通过具名捕获组(如 {id:\d+}、{category_slug})传递参数,由 FrontResolver 注入到请求上下文。
  • RESTful 路由:通过 declared 条目的 methods 字段限制 HTTP 方法(如 GET/POST/PUT/DELETE),配合资源型 URL 实现 CRUD 语义。

章节来源

  • front/route/page.php:15-31
  • front/route/product.php:15-30
  • front/route/article.php:15-30
  • front/foundation/routing/PrettyRouteMatcher.php:178-189

新页面定义、参数传递、URL 重写

  • 新页面:在 front/route 下新增 *.php,使用 Route::page / Route::column / Route::simple 声明式 API。
  • 参数传递:通过 pattern 中的具名捕获组(如 {id:\d+})传递参数,FrontResolver 将其合并到请求输入。
  • URL 重写:通过 config/route.php 的风格规则与短地址策略实现 URL 重写,确保生成与匹配一致。

章节来源

  • front/route/page.php:15-31
  • front/route/product.php:15-30
  • config/route.php:75-321

SEO 友好 URL 设计与最佳实践

  • 使用具名捕获组与明确边界,避免模糊匹配。
  • 优先选择语义化 URL(如 slug、category_slug),避免暴露内部 ID。
  • 启用短地址策略时,确保 URL 简洁且可逆。
  • 合理使用分页段(如 /oN)与归档段(如 /year/month),提升可读性与索引效果。

灵活定制指南

  • 覆盖风格:复制 config/route.php 为 route_custom.php,仅覆盖需要修改的风格。
  • 路由级中间件:通过 declared 条目的 mw_* 字段进行精细化控制(without/append/params/skip_all)。
  • 主题扩展:FrontResolver 会在控制器执行前加载主题扩展,便于按需增强功能。

章节来源

  • config/route.php:15-31
  • front/foundation/routing/FrontResolver.php:174-199
  • front/foundation/routing/FrontResolver.php:145-157
添加日期:2026-10-05