文档目录
URL生成器

简介

本技术文档面向DouPHP的URL生成子系统,围绕以下目标展开:

  • 基于路由名称生成URL、参数绑定、查询字符串处理机制
  • ShortUrlPolicy短地址模块策略(路径前缀省略、分类段替换等)
  • PrettyUrlCompiler美化URL编译(pattern迷你语言、双向可逆)
  • 完整示例覆盖静态页面、动态参数、分页、多语言、小程序
  • 性能优化与缓存策略
  • 版本管理与向后兼容建议

项目结构

URL生成子系统位于 core/web/routing 下,由四个核心类协作完成:

  • UrlGenerator:对外统一入口,封装调用面,负责声明式路由命中、意图解析、后端URL生成
  • UrlBuilder:具体路径构建器,按 kind 分发到 list/detail/category/class/action 等分支,并组合 ROOT_URL、语言前缀、分页
  • ShortUrlPolicy:短地址模块开关与路径工具(是否启用、前缀判断、前缀移除/补回)
  • PrettyUrlCompiler:pattern 迷你语言的编译器与填充器,保证入站匹配与出站生成一致
graph TB
A["业务代码<br/>route()/Url::xxx"] --> B["UrlGenerator<br/>统一入口"]
B --> C["UrlBuilder<br/>路径构建"]
C --> D["PrettyUrlCompiler<br/>pattern→路径"]
C --> E["ShortUrlPolicy<br/>短地址策略"]
B --> F["Admin/API端<br/>buildBackendUrl"]
C --> G["composeFullUrl<br/>ROOT_URL+语言+分页"]

核心组件

  • UrlGenerator:对外暴露 url()、urlMini()、getSlugPath()、warmupUrlCache();内部委托 UrlBuilder;对声明式条目优先走 RouteManifest 的 pattern 直接填充;对后台/API端输出绝对地址。
  • UrlBuilder:实现 buildFullUrl()、rewriteUrlMiniprogram()、warmupUrlCache()、getSlugPath();按 intent['kind'] 分发到不同路径构建方法;统一处理分页 /oN、语言前缀、伪静态开关。
  • ShortUrlPolicy:提供 isShort()、isPrefixedRoute()、prefixRoute()、stripModulePrefix() 等工具;支持 article→news 别名。
  • PrettyUrlCompiler:compileToRegex() 与 fill() 双向可逆;支持 {name}、{name:regex}、[optional] 语法;进程级正则缓存。

架构总览

URL生成流程分为“声明式命中”和“意图解析”两条主线:

  • 声明式命中:在浏览器端非小程序场景,先尝试通过 RouteManifest 获取具名 entry;若命中且为 declared 类型,则直接用 PrettyUrlCompiler 填充 pattern,并追加未消费参数为 query。
  • 意图解析:将点分路由键 + 具名参数解析为结构化 intent(list/detail/category/class/action2/action3),再由 UrlBuilder 构建路径片段,最后 composeFullUrl 拼接 ROOT_URL、语言前缀、分页。
sequenceDiagram
participant Caller as "调用方"
participant Gen as "UrlGenerator"
participant Manifest as "RouteManifest"
participant Builder as "UrlBuilder"
participant Compiler as "PrettyUrlCompiler"
participant Policy as "ShortUrlPolicy"
Caller->>Gen : url(route, params, options)
alt 非小程序且存在具名entry
Gen->>Manifest : getEntryByName(route)
alt 命中declared
Gen->>Compiler : fill(pattern, values)
Compiler-->>Gen : path
Gen->>Gen : 追加未消费参数为query
Gen-->>Caller : URL
else 未命中
Gen->>Gen : parseRouteToIntent()
Gen->>Builder : buildFullUrl(intent, page)
Builder->>Policy : 短地址策略判断
Builder->>Compiler : fill(pattern, values)
Builder-->>Gen : path
Gen-->>Caller : URL
end
else 小程序或后台/API
Gen->>Builder : buildMiniProgramUrl/buildBackendUrl
Builder-->>Gen : URL
Gen-->>Caller : URL
end

详细组件分析

UrlGenerator:统一入口与意图解析

  • 对外方法:
    • url(route, params, options):主入口,支持声明式条目直出、意图解析、后端绝对URL、查询串合并
    • urlMini(module, value, tabbar):小程序 pages 路径
    • getSlugPath(module, id, mode):slug 片段
    • warmupUrlCache(module, rows):列表预热
  • 关键逻辑:
    • 声明式条目优先:非小程序时先查 RouteManifest,若命中 declared 类型,直接 fill pattern 并追加未消费参数为 query
    • 意图解析:parseRouteToIntent 将 module.action 转为 kind/module/seg2/seg3/id/slug/category_id/class 等结构化字段
    • 后端URL:admin/api端以绝对地址输出,开启伪静态时 BASE&lt;path>,关闭时 BASE index.php?route=&lt;path>
flowchart TD
Start(["进入 url()"]) --> CheckDeclared{"是否存在具名entry?"}
CheckDeclared --> |是| FillPattern["fill pattern 并追加未消费参数"]
FillPattern --> Return1["返回URL"]
CheckDeclared --> |否| ParseIntent["parseRouteToIntent()"]
ParseIntent --> BuildPath["UrlBuilder.buildFullUrl()"]
BuildPath --> AppendQuery["追加options.query与未消费参数"]
AppendQuery --> Return2["返回URL"]

UrlBuilder:路径构建与完整URL组装

  • 主要职责:
    • buildFullUrl(intent, page):根据 kind 选择对应路径构建方法,再 composeFullUrl 拼接 ROOT_URL、语言前缀、分页
    • rewriteUrlMiniprogram(module, value, tabbar):小程序 pages 路径生成
    • warmupUrlCache(module, rows):批量预热 slug、created_at、category_id 等字段缓存
    • getSlugPath(module, id, mode):slug 片段,短地址模式下返回纯 slug 或顶级祖先别名
  • 路径构建分支:
    • list:page/column/其它模块根
    • detail:page 单页、single 模块、column 栏目详情
    • category:仅 column 模块的分类页
    • class:module/class/{class}
    • action2/action3:动作路径拼接
classDiagram
class UrlBuilder {
+buildFullUrl(intent, page) string
+rewriteUrlMiniprogram(module, value, tabbar) string
+warmupUrlCache(module, rows) void
+getSlugPath(module, id, mode) string
-buildPrettyPath(intent) string
-composeFullUrl(path, rewriteMode, page) string
-applyLanguagePrefix(path) string
-applyPagination(url, page, rewriteMode) string
}
class PrettyUrlCompiler {
+fill(pattern, values) string
+compileToRegex(pattern, params) string
}
class ShortUrlPolicy {
+isShort(baseModule) bool
+stripModulePrefix(path, urlModule, baseModule) string
+prefixRoute(route) string
}
UrlBuilder --> PrettyUrlCompiler : "填充pattern"
UrlBuilder --> ShortUrlPolicy : "短地址策略"

PrettyUrlCompiler:pattern 迷你语言编译器

  • 功能:
    • compileToRegex(pattern, params):将 pattern 编译为带具名捕获组的 PCRE,进程级缓存
    • fill(pattern, values):将 pattern 中的占位符替换为值,支持可选段 [...]
  • 语法:
    • {name}:默认子模式 [^/]+,可由 $params[name] 覆盖
    • {name:regex}:内联正则优先于 $params[name]
    • [ ... ]:可选段,fill 时任一占位符非空才渲染;compile 时编译为 (?:...)?
flowchart TD
Start(["fill(pattern, values)"]) --> Scan["扫描字符"]
Scan --> IsBracket{"是否'['"}
IsBracket --> |是| Optional["递归处理可选段"]
IsBracket --> |否| IsPlaceholder{"是否'{'"}
IsPlaceholder --> |是| Replace["提取name/regex并替换"]
IsPlaceholder --> |否| Append["追加字面量"]
Optional --> Next["继续扫描"]
Replace --> Next
Append --> Next
Next --> End(["返回规范化路径"])

ShortUrlPolicy:短地址模块策略

  • 功能:
    • enabled():判断短地址功能是否启用
    • isShort(baseModule):判断数据库模块是否为当前短地址模块
    • isPrefixedRoute(route):检测路径是否带有短地址模块前缀(避免长短URL并存)
    • prefixRoute(route):为解析端补回模块前缀重试
    • stripModulePrefix(path, urlModule, baseModule):移除生成路径开头的模块前缀
  • 特殊处理:article 模块映射为 news 别名

依赖关系分析

  • UrlGenerator 依赖:
    • RouteManifest:获取具名 entry 的 pattern 与 params
    • UrlBuilder:实际路径构建
    • PrettyUrlCompiler:pattern 填充
    • ShortUrlPolicy:短地址策略
  • UrlBuilder 依赖:
    • DB:读取 slug、created_at、category_id 等字段进行缓存预热
    • Config:读取 site.rewrite、site.short_url_module 等配置
    • Naming:模块名转换(如 article → news)
    • Util:查询串规范化
  • 小程序侧:
    • miniprogram/company/utils/route.ts:前端命名路由取址,与后端保持一致
    • miniprogram/company/config/site.ts:mp_url、rewrite_enable 等运行配置
graph LR
Gen["UrlGenerator"] --> BM["UrlBuilder"]
Gen --> PM["PrettyUrlCompiler"]
Gen --> SP["ShortUrlPolicy"]
BM --> DB["DB"]
BM --> CFG["Config"]
BM --> NAM["Naming"]
BM --> UT["Util"]
MP["小程序route.ts"] --> CFG

性能与缓存

  • 进程级缓存:
    • PrettyUrlCompiler::$regexCache:编译后的正则缓存,避免重复编译
    • UrlBuilder::$urlFieldCache:字段缓存(slug、created_at、category_id 等)
    • UrlBuilder::$urlCategoryCache:分类行缓存(表名 => [id => ['slug', 'parent_id']])
  • 列表预热:
    • warmupUrlCache(module, rows):批量预热 slug、created_at、category_id,减少逐条查库
  • 查询串规范化:
    • appendQuery() 使用 Util::normalizeQueryString 确保首个 & 转 ?,避免重复分隔符

优化建议:

  • 列表页务必调用 warmupUrlCache(),减少详情URL生成的数据库访问
  • 合理设置 config/route.php 的 pattern,避免复杂正则导致匹配开销
  • 短地址模块启用后,注意路径前缀一致性,避免长短URL并存

多语言与SEO

  • 多语言:
    • applyLanguagePrefix() 根据当前语言状态添加语言前缀(rewrite_open 模式或 lang=pack 查询串)
    • 小程序侧通过 mp_url 与 rewrite_enable 控制基础路径与伪静态
  • SEO:
    • PrettyUrlCompiler 支持 {year}/{month} 归档型规则,便于搜索引擎抓取
    • 短地址模块可省略模块名段,提升URL可读性
    • 分类页支持 category_slug 别名,增强语义化

短链接策略

  • 短地址模块:
    • 通过 site.short_url_module 与 features.&lt;short> 控制启用
    • 启用后,该模块的URL省略模块名段(如 item/fenleiyi → fenleiyi)
    • 分类段取顶级祖先别名(短地址家族)或自身别名(普通模块)
  • 冲突处理:
    • isPrefixedRoute() 检测带前缀的路径,避免长短URL并存
    • stripModulePrefix() 移除生成路径的前缀,确保输出一致
  • 存储管理:
    • 通过 getSlugPath() 与 warmupUrlCache() 读取 slug、category_id 等字段,结合数据库表结构管理

URL版本管理与兼容性

  • 版本管理:
    • 通过 config/route.php 的 pattern 定义URL形态,升级时可调整 pattern 而不影响业务代码
    • 声明式路由(RouteManifest)提供单一真相源,前后端共享同一份规则
  • 向后兼容:
    • 关闭伪静态时自动回退 index.php?route=&lt;path> 形态,确保旧环境兼容
    • 小程序侧通过 rewrite_enable 控制路径形态,与后端保持一致
    • 短地址模块启用后,解析端可补回前缀重试,避免历史链接失效

使用示例

  • 静态页面:
    • route('page.show', ['slug' => 'agreement'])
  • 动态参数:
    • route('article.show', ['id' => 123])
    • route('product.category', ['category_id' => 5])
  • 多语言支持:
    • 自动根据当前语言状态添加语言前缀或 lang=pack 查询串
  • 小程序:
    • 使用 miniprogram/company/utils/route.ts 的 route(name, params) 生成pages路径
    • 通过 site.ts 的 mp_url 与 rewrite_enable 控制基础路径与伪静态

故障排查

  • 常见问题:
    • URL生成失败:检查 route 键是否正确,params 是否包含必需字段(id、category_id、slug等)
    • 短地址冲突:确认 short_url_module 配置与 features.&lt;short> 开关一致
    • 伪静态问题:检查 site.rewrite 配置与服务器重写规则
  • 调试建议:
    • 使用 Url::getSlugPath() 检查slug片段是否正确
    • 使用 Url::warmupUrlCache() 预热列表页数据,减少数据库压力
    • 检查 PrettyUrlCompiler 的 pattern 是否符合语法规则

结论

DouPHP的URL生成系统通过UrlGenerator、UrlBuilder、ShortUrlPolicy、PrettyUrlCompiler四大组件协同工作,实现了:

  • 基于路由名称的URL生成与参数绑定
  • 短地址模块的策略化处理
  • 美化URL的pattern编译与填充
  • 多语言、分页、SEO优化
  • 高性能缓存与列表预热
  • 版本管理与向后兼容

开发者可通过route()助手函数快速生成URL,高级用户可自定义pattern与策略以满足特定需求。

添加日期:2026-10-05