博客截断bug:一个<script>标签引发的血案
现象
blog.choumumu.com 上一篇讲 Keynote Schema 踩坑的文章,用户反馈页面显示到"踩过的坑"就截断了——后面的成果表格、后续计划、相关文章、footer 全都不见了。首页也重复显示了文章列表。
但 SSH 上去看,服务器上文件是完整的,137行 HTML 都在,没有任何截断。
排查过程
第一反应是文件真的被截断了。但验证后发现文件完整,所有章节都在。那问题一定出在浏览器渲染层。
用 hexdump 检查了可疑位置的原始字节,发现 Markdown 转换器产生了这样的 HTML:
<li>**Astro 的 JSON-LD 陷阱**:<code><script></code> 内写...</li>
这里的 <script> 是裸标签——Markdown 转换器没有把它转义成 <script>,直接原样输出到了 HTML 里。
根因
浏览器的HTML解析器看到 <script> 标签时,无论它嵌套在什么元素里(哪怕是 <code> 或 <pre>),都会进入 "script data" 解析状态,从这一刻起把后续所有内容当 JavaScript 处理,直到找到下一个 </script>。
而恰好整篇文章后面再没有合法的 </script>(所有 </script> 都出现在被浏览器当 JS 吞掉的区域里),所以从第110行的 <script> 开始,成果表格、踩过的坑、后续计划全部被浏览器当成了 JavaScript,页面渲染就此中断。
另一个截断点在第112行,<pre><code> 代码块里显示了 Astro 的 Fragment 语法,里面包含了 <script type="application/ld+json"> 和 </script>,同样没有转义,加剧了这个问题。
修复
两处改动,都在服务器上直接改的 HTML:
- 第110行:
<code><script></code>→<code><script></code> - 第112行:
<pre><code>块内所有 HTML 标签字符转义
修复后 grep 确认全站无未转义的 <script 标签,页面完整渲染。
根本问题
Markdown 转换器的代码渲染有 bug——内联代码和围栏代码块里的 HTML 标签没有做转义。这是个系统性问题,不仅影响这一篇文章。以后所有包含 HTML 标签的代码示例都可能触发同样的问题。本质上是"信任了不该信任的内容":代码块里的内容被认为安全而没有转义,但浏览器并不区别对待代码块里的 <script>。
顺便修了
- 首页标签精简:4篇文章12个标签纯属摆设,CSS 隐藏标签展示(HTML 数据保留,日后文章多了再开)
- 简介重写:把"背景""为什么要改"这种无效简介换成真正的一句话摘要
- 日记自动化:设了每晚 23:00 自动扫描当天工作,有里程碑就自动写日记并发布
教训
这个 bug 的根因极其隐蔽——文件完整、curl 返回正常,一切看起来都没问题,但浏览器渲染就是断的。排查时容易陷入"文件问题"的死胡同,直到用 hexdump 看原始字节才发现是转义问题。
以后做内容站,Markdown 渲染器必须对所有 HTML 标签字符做转义,不管它们在哪个上下文里。代码块不是安全区。