恰好准备换卡,在 qrz.com 上整理了一下个人简介。翻了翻编辑页面,发现 Bio 支持 HTML语法,于是写了一份带样式的 Html,加了颜色、字号、间距。保存,刷新,结果页面上只剩开头一截。
第一反应是触发了 qrz 的安全过滤。HTML 里有 style 属性,说不定被当成 XSS 风险砍掉了。于是改成最朴素的 <table><td> 结构,内联样式都去掉,再试一次还是一样,保存后内容依然面目全非,只剩个开头残躯。div 标签被强制闭合,但是手动添加文字进去又能够正常保存。
qrz 的 Bio 并不是直接嵌在页面 HTML 里的,用开发者工具翻了一圈,内容藏在渲染 Bio 简介的 <iframe> 下的 <script> 里,用 Base64 编码塞进去,关键部分长这样:
| |
把这段 Base64 解码出来,截断的位置恰好卡在 <p style="color: #0050E6; font-size: 24px; font-weight: bold; margin: 0 0 5px 0;"> 后面原本紧跟着一个Emoji 👋 字符。Emoji 以及之后的所有内容全没了。
这个现象指向一个很经典的历史遗留问题。MySQL 等数据库后端早年的 utf8 字符集是个残缺实现,每个字符最多只存 3 个字节。这对绝大多数文字来说够用,但 Unicode 中的 Emoji 字符需要 4 个字节来编码。一旦数据库列的字符集是 utf8 而非后来补全的 utf8mb4,写入时碰到第一个 4 字节字符,就会直接在那里截断,后面的内容全部丢弃。
qrz.com 是一个运营了很久的老站,底层用的大概率正是这套配置。
把 Bio 里所有 Emoji 删掉,保存,立刻生效。
如果不去翻 Base64 编码的内容,浏览器又自动把截断的标签补上了,大概会一直以为是 HTML 过滤在作怪,然后在哪些标签被允许上兜圈子兜很久。
有时候问题的答案藏得比预期深一点,多翻一层就能看见。
