博客优化总结:从 iframe 被转义到完美支持网易云音乐播放器
摘要
在博客中插入网易云音乐播放器时,文章显示转义文本。经排查,发现数据库存储的是纯文本节点而非HTML。最终采用前端动态替换方案:利用TreeWalker遍历文本节点,识别包含data-netease-id的节点并解析ID,动态创建iframe替换原文本。此方案无需修改数据库和后端,支持歌曲与播客,且移动端适配良好。
一、问题背景
使用基于 Cloudflare Workers + D1 数据库 + React (TanStack Router) + TipTap 编辑器的博客系统(flare-stack-blog,Fuwari 主题),希望在 Markdown 文章中插入网易云音乐的外链播放器(iframe 插件)。标准的 iframe 代码在文章中编写后,前端不显示播放器,而是显示被转义后的文本(如 <iframe...)。
二、探索与排查路径
2.1 初步检查:CSP 与前端渲染
· 假设:可能是 Content Security Policy 限制了 iframe 加载。
· 验证:检查浏览器 Network 面板响应头,未发现 CSP 限制;直接写测试 HTML 能正常显示播放器,排除 CSP 问题。
2.2 定位转义发生位置
· 发现前端页面中 iframe 代码被转义为 HTML 实体(<iframe...),这意味着转义发生在数据到达浏览器之前。
· 博客文章数据存储流程:Markdown 源码 → 后端/构建时转换为 TipTap JSON → 存入 D1 数据库 → 前端 ContentRenderer 组件渲染 JSON。
· 确认转义发生在“Markdown → JSON”的转换阶段,或数据库存储时对 HTML 进行了编码。
2.3 尝试修改 Markdown 解析器(不成功)
· 找到 markdown-parser.ts,其中使用 marked 将 Markdown 转 HTML,再用 TipTap 的 DOMParser 将 HTML 转为 JSONContent。
· 尝试为 TipTap schema 添加 IframeExtension 自定义节点,使 iframe 能被解析为合法节点。
· 失败原因:该解析器仅用于后台导入/导出功能,并非前台文章发布时使用的转换逻辑。前台文章发布走的是另一条路径(可能是 Admin 面板直接保存 TipTap JSON,未经过此解析器)。
2.4 检查路由与布局组件
· 找到文章展示的 PostPage 组件(src/features/theme/themes/fuwari/pages/post/page.tsx),其中使用 <ContentRenderer content={post.contentJson} /> 渲染。
· 尝试在 PostPage 中用 useEffect 动态创建 iframe,但页面中只能看到转义后的纯文本(<div data-netease-id...),querySelector 无法捕获任何 DOM 元素。
· 核心发现:数据库中 content_json 字段存储的不是 HTML 标签,而是包含转义字符串的纯文本节点。例如:
渲染后直接在页面上显示为字符串 "<div data-netease-id=...>",而不是一个可被 JS 操作的 HTML 元素。
2.5 最终解决方案:前端文本节点替换
· 不再尝试修复数据库或转换逻辑,而是在浏览器端直接操作 DOM 文本节点。
· 使用 TreeWalker 遍历 .fuwari-custom-md 容器内的所有文本节点,找到包含 data-netease-id 的文本,解析出歌曲 ID,动态创建 <iframe> 并替换该文本节点。
· 同时处理实体编码版本(<div data-netease-id="...">)和原始尖括号版本。
2.6 适配与扩展
· 移动端适配:将 iframe 宽度设为 100%,最大宽度 409px,保证小屏幕自适应。
· 支持播客(type=3):增加 data-netease-type 属性解析,在 iframe 的 src 中动态设置 type 参数。
三、关键发现与反思
3.1 操作过程回顾
问题阶段 | 错误假设 | 正确结论 |
|---|---|---|
初期 | CSP 阻止 | iframe 无 CSP 限制,是内容转义问题 |
中期 | Markdown 解析器是罪魁祸首 | 该解析器未被实际使用,前台文章通过另一路径存储 JSON |
后期 | 修改布局组件插入 JS 能解决问题 | 数据库中已存为纯文本,无法被 DOM 选择器捕获 |
最终 | 必须修改数据库或转换逻辑 | 前端文本节点替换绕过了所有存储缺陷 |
3.2 教训
· 不要轻易假设代码的执行路径,应通过搜索调用关系确认功能归属。
· 当数据在传输/存储过程中已变形,前端动态替换是快速有效的修复手段。
· 对于已上线的博客,最小侵入性修复(不改数据库、不改后端)是首选。
四、最终方案的技术实现
文章中只需写入:
五、优化成果
· 无需修改数据库,不影响已有数据,零风险。
· 无需修改后端转换逻辑,避免侵入性改动。
· 支持歌曲和播客,并通过属性扩展支持其他类型(如歌单 type=1)。
· 移动端完美适配,播放器自动缩放。
· 编写文章时只需简单的 HTML 占位符,比原 iframe 更简洁且不会被转义。
· 解决了根本问题:无论将来数据库如何存储,前端都能可靠转换。
六、可能的进一步优化方案
如果后续希望彻底根治,可以:
1. 修改 Admin 后台的 Markdown→JSON 转换逻辑,增加 IframeExtension 并正确存储为自定义节点。
2. 写数据迁移脚本,将现有文本节点中的 data-netease-id 占位符转换为真正的 neteasePlayer 节点。
3. 最终移除前端的文本节点替换逻辑,使数据流更干净。
但目前的前端方案已经足够稳定,且维护成本极低。
七、总结
本次优化是一次典型的前端“绕行”修复案例,展示了在无法快速修改后端存储结构的情况下,如何利用浏览器 DOM API 实现功能,同时保留了未来重构的可能性。最终博客体验得到提升,也积累了宝贵的调试经验。
相关文章
暂无相关文章
