# `Url2File` 与 `TmplUrl2File` 技术文档 > **模块功能概述** 该模块提供了将 URL 映射到本地文件系统路径的工具类,主要用于 Web 服务或模板引擎中实现 URL 到文件路径的解析。支持虚拟路径映射、目录索引查找、路径继承(父级回退)以及相关资源定位等功能。 --- ## 模块依赖 ```python import os ``` > 注意:`listFile()` 函数在代码中被调用但未定义,可能是外部导入函数,用于递归列出指定后缀的文件。 --- ## 类一:`Url2File` ### 功能说明 将符合特定规则的 URL 转换为本地文件系统的绝对路径,并支持自动查找默认索引页、处理相对路径(如 `..` 和 `.`)、查询关联资源等。 ### 构造函数:`__init__(path: str, prefix: str, indexes: list, inherit: bool = False)` #### 参数说明 | 参数 | 类型 | 说明 | |------|------|------| | `path` | `str` | 根目录路径,URL 将映射到此路径下的子目录结构。 | | `prefix` | `str` | URL 前缀,用于标识哪些 URL 应由该实例处理(目前仅存储,未直接使用)。 | | `indexes` | `list[str]` | 索引文件名列表,例如 `['index.html', 'default.htm']`,当请求的是一个目录时,尝试返回这些文件之一。 | | `inherit` | `bool` | 是否启用“继承模式”。若为 `True`,当当前路径无匹配文件时,会向上一级 URL 路径回溯查找。 | #### 示例初始化 ```python u2f = Url2File("/var/www/html", "/static", ["index.html"], inherit=True) ``` --- ### 方法列表 #### 1. `realurl(url: str) -> str` **功能**:规范化 URL,去除 `.` 和 `..` 等逻辑路径片段。 **参数** - `url` (`str`):原始 URL 路径部分(不含协议) **返回值** - 规范化后的 URL 字符串 **算法说明** - 分割 `/` 得到路径项 - 移除所有 `.` 项 - 遇到 `..` 时,与其前一项配对删除(模拟上级目录跳转) - 最终重新拼接为标准路径 **示例** ```python u2f.realurl("a/b/../c") # → "a/c" u2f.realurl("a/./b//c") # → "a/b//c" (注意双斜杠不会被修复) ``` > ⚠️ 注意:本方法不处理重复斜杠,也不验证是否存在真实路径。 --- #### 2. `url2ospath(url: str) -> str` **功能**:将完整 URL 转换为本地操作系统的绝对路径。 **参数** - `url` (`str`):输入的 URL(可带查询参数) **返回值** - 对应的本地文件系统绝对路径(尚未验证文件是否存在) **处理流程** 1. 去除查询字符串(`?` 后内容) 2. 去除末尾 `/` 3. 若以 `http://`, `https://`, `ws://`, `wss://` 开头,则跳过协议头(前三段:协议 + 主机 + 端口/空) 4. 使用 `os.path.join(self.rootpath, *paths)` 构建路径 5. 返回 `abspath` 绝对路径 **示例** ```python u2f = Url2File("/var/www", "/app", ["index.html"]) u2f.url2ospath("https://example.com/app/user/profile") # → /var/www/user/profile ``` --- #### 3. `url2file(url: str) -> str or None` **功能**:根据 URL 查找对应的本地文件路径,是核心方法。 **参数** - `url` (`str`):请求的 URL **返回值** - 匹配的本地文件路径(`str`),否则返回 `None` **查找逻辑** 1. 先去除查询参数 2. 转换为本地路径 `real_path` 3. 如果 `real_path` 是一个存在的目录: - 遍历 `self.indexes` 中的索引文件名 - 检查 `/` 是否存在文件,第一个存在的即返回 4. 如果 `real_path` 是一个存在的文件 → 直接返回 5. 如果父目录不存在 → 返回 `None` 6. 如果 `inherit=False` → 不允许继承,返回 `None` 7. 如果允许继承且路径层级 > 2: - 删除倒数第二级路径(向上回退一级) - 递归调用自身进行重试 8. 所有尝试失败 → 返回 `None` **示例行为** ```python # 假设目录结构: # /www/root/ # └── a/ # └── b/ # └── index.html u2f = Url2File("/www/root", "/site", ["index.html"], inherit=True) u2f.url2file("/site/a/b/") # → /www/root/a/b/index.html u2f.url2file("/site/a/b") # → 同上(自动识别为目录) u2f.url2file("/site/a/c") # → 尝试 /www/root/a/c → 不存在 → 回退到 /site/c?不准确! # 实际继承逻辑:删除倒数第二段 → /site/a/c → 删除 a → /site/c # 即:/a/c 失败 → 尝试 /c ``` > 🔍 继承机制适用于某些扁平化模板 fallback 场景,但需谨慎设计路径结构避免误匹配。 --- #### 4. `relatedurl(url: str, name: str) -> str` **功能**:获取与当前 URL 相关的另一个资源的逻辑 URL。 **参数** - `url` (`str`):当前上下文 URL - `name` (`str`):目标资源名称(文件或子路径) **返回值** - 新的逻辑 URL(规范化后) **逻辑** - 若原 URL 以 `/` 结尾,先去掉末尾 `/` - 使用 `url2ospath` 获取对应路径并判断是否为文件 - 如果是文件,则将其所在目录作为基准路径(即去掉最后一段) - 拼接新 `name` 成新路径 - 调用 `realurl()` 进行规范化 **用途举例** ```python # 当前页面是 /user/profile,想引用同级的 avatar.png relatedurl("/user/profile", "avatar.png") # → /user/avatar.png relatedurl("/user/", "style.css") # → /user/style.css ``` --- #### 5. `relatedurl2file(url: str, name: str) -> str or None` **功能**:结合 `relatedurl` 和 `url2file`,查找与某 URL 相关的文件。 **参数** - `url` (`str`):当前上下文 URL - `name` (`str`):目标文件名 **返回值** - 目标文件的本地路径(`str`),否则 `None` **内部流程** 1. 调用 `self.relatedurl(url, name)` 2. 再调用 `self.url2file(...)` 查询该路径对应的文件 **示例** ```python u2f.relatedurl2file("/user/profile", "config.json") # → 可能返回 /www/root/user/config.json ``` --- ## 类二:`TmplUrl2File` ### 功能说明 管理多个 `Url2File` 实例,支持多路径搜索、模板文件扩展名过滤,常用于模板或静态资源加载器。 ### 构造函数:`__init__(paths, indexes, subffixes=['.tmpl','.ui'], inherit=False)` #### 参数说明 | 参数 | 类型 | 说明 | |------|------|------| | `paths` | `List[Tuple[str, str]]` | 元组列表,每个元素为 `(本地根路径, URL前缀)` | | `indexes` | `list[str]` | 索引文件名列表(传递给每个 `Url2File`) | | `subffixes` | `list[str]` | 模板文件的扩展名,默认为 `['.tmpl', '.ui']` | | `inherit` | `bool` | 是否开启继承查找(统一传给所有 `Url2File`) | > ❗ 注意:虽然 `prefix` 存储于 `Url2File` 中,但在当前实现中并未用于路由匹配,所有 `url2file` 请求都会遍历全部 `u2fs` 实例。 #### 示例初始化 ```python tmpl_u2f = TmplUrl2File( paths=[ ("/opt/templates/custom", "/theme"), ("/opt/templates/default", "/") ], indexes=["index.tmpl"], subffixes=[".tmpl", ".html"], inherit=True ) ``` --- ### 方法列表 #### 1. `url2file(url) -> str or None` **功能**:依次尝试各个 `Url2File` 实例来查找文件。 **逻辑** - 遍历 `self.u2fs` - 调用每个实例的 `url2file(url)` - 返回第一个成功结果 - 全部失败 → 返回 `None` **用途** - 实现“自定义模板覆盖默认模板”的优先级查找机制 --- #### 2. `relatedurl(url: str, name: str) -> str or None` **功能**:查找第一个能生成有效相关 URL 的 `Url2File` 实例。 > ⚠️ 当前实现存在问题:即使某个 `relatedurl` 返回非空字符串,也可能不是合法路径或无法访问文件。 **建议改进**:应结合 `relatedurl2file` 思路,确保结果有意义。 --- #### 3. `list_tmpl() -> List[str]` **功能**:列出所有配置路径下、符合指定后缀的模板文件(绝对路径)。 **返回值** - 排序后的文件路径列表(`List[str]`) **实现细节** - 遍历 `self.paths` 中的每个根路径 `rp` - 转为绝对路径 - 调用 `listFile(p, suffixs=self.subffixes, recursive=True)` 递归查找匹配文件 - 收集进 `ret` 列表 - 最终排序返回 > 📌 依赖外部函数 `listFile(dir, suffixs=[], recursive=False)`,其功能推测如下: > > ```python > def listFile(directory, suffixs=None, recursive=False): > matches = [] > for root, dirs, files in os.walk(directory): > for f in files: > if any(f.endswith(suf) for suf in suffixs): > matches.append(os.path.join(root, f)) > if not recursive: > break > return matches > ``` **典型输出示例** ```python [ '/opt/templates/default/home.tmpl', '/opt/templates/default/layout.ui', '/opt/templates/custom/theme.dark.tmpl' ] ``` --- ## 使用场景示例 ### 场景 1:Web 模板引擎路径映射 ```python loader = TmplUrl2File( paths=[("/web/tmpl/custom", "/"), ("/web/tmpl/base", "/")], indexes=["page.tmpl"], subffixes=[".tmpl"], inherit=True ) # 用户请求 /user/list template_path = loader.url2file("/user/list") # → 先查 custom/user/list → 存在则返回 # → 不存在则查 base/user/list → 或继续回退至 /list(如果 inherit=True) ``` ### 场景 2:静态资源 fallback ```python static = Url2File("/public", "/static", ["index.html"], inherit=True) static.url2file("/static/js/app.js") # → /public/js/app.js static.url2file("/static/missing.jpg") # → 查不到 → 回退到 /static → 仍失败 → None ``` --- ## 注意事项与改进建议 | 问题 | 描述 | 建议 | |------|------|------| | `prefix` 未实际参与路由 | `Url2File.prefix` 仅保存未使用,可能导致误解 | 可增加前缀匹配逻辑,或移除该字段 | | `realurl` 不处理重复斜杠 | `"a//b"` 不会被标准化为 `"a/b"` | 可添加正则替换 `re.sub(r'/+', '/', ...)` | | `listFile` 未定义 | 导致模块不可独立运行 | 应补充定义或明确声明依赖 | | `relatedurl` 返回可能无效 | 仅生成 URL 字符串,不保证路径存在 | 改为返回 `(url, filepath)` 或集成存在性检查 | | 多路径查找顺序敏感 | `paths` 顺序决定优先级 | 文档中应强调顺序重要性 | --- ## 版权与许可 © 2025 项目作者。可用于内部系统或 Web 框架中的资源映射层。请确保遵守操作系统权限与安全规范。 --- ✅ **推荐用途**:轻量级模板/静态文件路由映射、开发服务器路径解析、MVC 架构视图定位组件。