10 KiB
Url2File 与 TmplUrl2File 技术文档
模块功能概述
该模块提供了将 URL 映射到本地文件系统路径的工具类,主要用于 Web 服务或模板引擎中实现 URL 到文件路径的解析。支持虚拟路径映射、目录索引查找、路径继承(父级回退)以及相关资源定位等功能。
模块依赖
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 路径回溯查找。 |
示例初始化
u2f = Url2File("/var/www/html", "/static", ["index.html"], inherit=True)
方法列表
1. realurl(url: str) -> str
功能:规范化 URL,去除 . 和 .. 等逻辑路径片段。
参数
url(str):原始 URL 路径部分(不含协议)
返回值
- 规范化后的 URL 字符串
算法说明
- 分割
/得到路径项 - 移除所有
.项 - 遇到
..时,与其前一项配对删除(模拟上级目录跳转) - 最终重新拼接为标准路径
示例
u2f.realurl("a/b/../c") # → "a/c"
u2f.realurl("a/./b//c") # → "a/b//c" (注意双斜杠不会被修复)
⚠️ 注意:本方法不处理重复斜杠,也不验证是否存在真实路径。
2. url2ospath(url: str) -> str
功能:将完整 URL 转换为本地操作系统的绝对路径。
参数
url(str):输入的 URL(可带查询参数)
返回值
- 对应的本地文件系统绝对路径(尚未验证文件是否存在)
处理流程
- 去除查询字符串(
?后内容) - 去除末尾
/ - 若以
http://,https://,ws://,wss://开头,则跳过协议头(前三段:协议 + 主机 + 端口/空) - 使用
os.path.join(self.rootpath, *paths)构建路径 - 返回
abspath绝对路径
示例
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
查找逻辑
- 先去除查询参数
- 转换为本地路径
real_path - 如果
real_path是一个存在的目录:- 遍历
self.indexes中的索引文件名 - 检查
<dir>/<index_file>是否存在文件,第一个存在的即返回
- 遍历
- 如果
real_path是一个存在的文件 → 直接返回 - 如果父目录不存在 → 返回
None - 如果
inherit=False→ 不允许继承,返回None - 如果允许继承且路径层级 > 2:
- 删除倒数第二级路径(向上回退一级)
- 递归调用自身进行重试
- 所有尝试失败 → 返回
None
示例行为
# 假设目录结构:
# /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):当前上下文 URLname(str):目标资源名称(文件或子路径)
返回值
- 新的逻辑 URL(规范化后)
逻辑
- 若原 URL 以
/结尾,先去掉末尾/ - 使用
url2ospath获取对应路径并判断是否为文件 - 如果是文件,则将其所在目录作为基准路径(即去掉最后一段)
- 拼接新
name成新路径 - 调用
realurl()进行规范化
用途举例
# 当前页面是 /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):当前上下文 URLname(str):目标文件名
返回值
- 目标文件的本地路径(
str),否则None
内部流程
- 调用
self.relatedurl(url, name) - 再调用
self.url2file(...)查询该路径对应的文件
示例
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实例。
示例初始化
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),其功能推测如下: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
典型输出示例
[
'/opt/templates/default/home.tmpl',
'/opt/templates/default/layout.ui',
'/opt/templates/custom/theme.dark.tmpl'
]
使用场景示例
场景 1:Web 模板引擎路径映射
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
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 架构视图定位组件。