数优编码 All articles
编码原理

从「锟斤拷」到 Emoji 崩库:一场字符编码引发的血案复盘

数优编码
从「锟斤拷」到 Emoji 崩库:一场字符编码引发的血案复盘

Photo: Tamatak 'v chamatak ki, Public domain, via Wikimedia Commons

如果你在美国公司写代码,可能觉得字符编码是个「上世纪的话题」。直到某天,你的系统收到一条来自上海合作伙伴的数据,页面上赫然显示着「锟斤拷」三个大字——恭喜,你正式加入了乱码受害者俱乐部。

一切从 7 个 bit 说起

1963 年,ASCII 用 7 个 bit 定义了 128 个字符:英文字母、数字、一些标点,外加一堆现在已经没人用的控制字符。对英语世界来说,这够用了,甚至可以说完美。美国工程师拍拍手:「搞定,收工。」

问题在于,世界上大部分人的母语不是英语。中文有上万个汉字,ASCII 那 128 个位置连零头都不够。于是各国各显神通:欧洲人把第 8 个 bit 用起来搞出 ISO-8859 系列,中国则制定了 GB2312,后来演化为 GBK——用两个字节表示一个汉字。

GBK 的幽灵仍在游荡

很多开发者以为 GBK 已经进了博物馆。醒醒吧:国内的银行系统、政府平台、老牌 ERP,大量仍在使用 GBK/GB18030。当你的美国公司需要对接这些系统时,编码问题就会以最丑陋的方式浮出水面。

举个真实场景:你的服务用 UTF-8 发送订单备注,对方系统按 GBK 解析。两个字节的 UTF-8 中文被强行配对成 GBK 字符,输出一串谁也不认识的「鍝堝搱」。这不是段子,这是每年无数跨国集成项目里真实发生的日常。

UTF-8 为什么赢下了互联网

Unicode 的想法很朴素:给全世界所有字符发一张唯一的身份证(码点)。但怎么在字节流里存储这些码点,各方吵翻了天。UTF-16 固定用两字节起步,对英文浪费空间;UTF-32 更是奢侈。

Ken Thompson 和 Rob Pike(就是写 Go 和 Unix 的那两位)设计的 UTF-8 用了巧妙的变长方案:英文字符 1 字节,常用中文 3 字节,Emoji 4 字节。它向后兼容 ASCII,没有字节序问题,且自同步——从字节流中间开始读也不会错位。于是它一路碾压,如今 98% 以上的网页都是 UTF-8。

乱码排查实战手册

遇到乱码别慌,按这个顺序查:

  1. 确认原始字节。用 hex viewer 看原始数据,别相信任何一层已经「渲染」过的显示。EF BF BD(U+FFFD 替换字符)出现说明数据在某一环已经被不可逆地损坏了。
  2. 定位损坏点。在数据链路的每一环(客户端 → API → 数据库 → 前端)打日志,看编码从哪一层开始变味。
  3. 检查 MySQL 的隐性坑。老的 utf8 其实是阉割版,最多 3 字节,存不了 Emoji。用 utf8mb4,别问为什么。
  4. HTTP 头 vs meta 标签。Content-Type: text/html; charset=utf-8 响应头优先级高于页面里的 meta 标签,两边不一致时浏览器听头的。
  5. 文件读写显式指定编码。new String(bytes) 这种不指定 charset 的代码,在 Linux 上能跑、换台机器就炸,是经典的「在我机器上是好的」来源。

写在最后

编码知识就像消防演习——平时没人想起,出事时决定生死。花一个下午把这套原理吃透,你省下的可能是未来某个凌晨三点的 production 事故复盘会。数优编码后续会推出 GB18030 与 UTF-8 互转的专项指南,敬请期待。

All Articles

Related Articles

面试官问「Base64 能保护数据吗」:90% 候选人都答错了

面试官问「Base64 能保护数据吗」:90% 候选人都答错了