7.3 富文本处理
概述
富文本的核心是 [IMG_URL] 持久化契约:存库时本站图片引用转为占位符(LocalizeContentFields),读取时还原为访问基址(ExpandContentFields,唯一还原出口)。content 字段的库内格式是系统私有契约。
转换流图
text
写侧 LocalizeContentFields(content, saveDir):
正文 HTML
│ 正则提取 img/video/source/embed[src] + a[href(带后缀)]
│ 逐 URL 判断:
│ 含 /temp/ → SaveFromTemp 转正 → "[IMG_URL]/user/.../x.png"
│ 本站正式路径 → 剥离 domainUrl → "[IMG_URL]/user/.../x.png"
│ 外站 http(s) → 跳过(不处理,规避 SSRF)
▼
库存 content(含 [IMG_URL] 占位符;此为持久化格式契约)
读侧 ExpandContentFields(content):
"[IMG_URL]" ──ReplaceAll──▶ 访问基址(GetAccessBase)──▶ 前端富文本展示
唯一还原出口;ModuleSpec.ContentFields 声明后两侧自动接入契约要点
[IMG_URL] 是持久化契约
[IMG_URL]是库内 content 字段格式的一部分——content 不供第三方系统直接消费- 还原只能走
ExpandContentFields——业务代码禁止手写字符串替换 - 读取必须走 Detail/List(基座 ContentFields 自动 Expand)——直接 Struct 输出会漏还原
- 外站 URL 不本地化不替换(设计边界:防 SSRF 与外链下载)
声明式接入(ModuleSpec)
go
ContentFields: []string{"content"}, // 读写两侧自动接入
FileSaveDir: "article", // 内嵌 temp 图片的转正目录接入后基座自动完成:
text
写侧(Add/Update → saveTransform):
LocalizeContentFields 处理 content(temp 图片转正 + 占位符化)
读侧(Page/Detail → readTransform):
ExpandContentFields 还原占位符为访问基址article.content 是典型接入字段;未接入 ContentFields 的模块需手动调 base.go 两个函数(不推荐)。
匹配范围(写侧正则)
text
img[src] / video[src] / source[src] / embed[src]
a[href](仅带文件后缀的链接——普通网页链接不处理)普通 <a href="https://example.com"> 外链保持原样(是超链接不是资源引用)。
前端协作
text
编辑器(TinyMCE/Quill):
上传图片走 /api/upload/uploadFile → 得到 temp URL → 插入编辑器
编辑器内容即正文 HTML(含 temp URL)
保存:正文提交 → 后端 LocalizeContentFields 转正+占位符化 → 入库
回显:Detail 返回已还原的完整 URL → 编辑器直接渲染
再次编辑:取 Detail 内容 → 编辑 → 保存(循环;已正式的图片引用保持稳定)排障
| 症状 | 原因 |
|---|---|
| 富文本图片不显示 | 读取绕过了基座(直接 Struct);或 domainUrl 配置错(还原基址不对) |
| 库里看到 [IMG_URL] | 正常——库内契约格式;接口输出应已还原 |
| 外站图片 404 | 外站 URL 不本地化是设计边界;如需本地化要另行开发(注意 SSRF 防护) |
| 图片重复转正 | 正式路径引用幂等(归一化原样返回),不会重复移动;temp 引用每次编辑会重新转正(保存前应已在阶段一转正) |
| 第三方系统读 content 乱码 | content 是私有契约——第三方消费应走 Detail 接口(已还原)而非直读库 |