在阿里云上做开发和运维,乱码几乎躲不开。同一段中文,在终端、数据库、对象存储和网页里可能显示成完全不同的样子。多数情况下,原因是某一环的编码声明和其他环节对不上。

一、乱码通常出在哪一环
文字很少在存储过程中自己损坏。更常见的是,一方按 UTF-8 写入,另一方按 GBK 或 ISO-8859-1 去读,字节自然对不上。排查时,先把数据经过的环节列出来,再逐个确认:
- SSH 客户端:Xshell、SecureCRT 的会话编码是否设为 UTF-8。
- 服务器 locale:执行
locale,看 LANG 和 LC_* 变量是否指向 UTF-8 语言环境。 - 数据库:执行
SHOW VARIABLES LIKE 'character_set%';看服务端和连接的字符集,再检查应用的连接串有没有显式声明。 - HTTP 响应头和页面:用
curl -I看返回的 Content-Type 里有没有 charset。 - 文件本身:用
file -i 文件名查看实际保存的编码。
二、案例一:ECS 终端里中文显示成问号
某电商团队在新购的 ECS 实例上运行部署脚本,日志里的中文全部变成问号。一开始他们怀疑程序写错了。实际排查后发现,系统 locale 被设成了 POSIX。部分程序会读取环境变量判断输出编码,于是输出异常。
处理方法是先用 echo $LANG 和 locale 查看当前设置,再用 locale -a 确认系统里已经生成了对应的语言环境。确认后,把 LANG 改为 en_US.UTF-8 或 zh_CN.UTF-8。如果列表里没有,需要先安装语言包再改。
客户端也要检查。Xshell、SecureCRT 需要在会话属性里把字符编码设为 UTF-8。否则服务器输出是正确的,屏幕上仍会显示异常,很容易被误判为服务器的问题。
三、案例二:数据库迁移后中文变成“欢返
一家内容平台把旧库从自建 MySQL 迁移到阿里云 RDS,页面上的中文全部变成类似“欢返的字符串。旧表使用 latin1 字符集存储,而 UTF-8 字节被当作 latin1 写入,数据在写入那一刻就已经错位。
这种情况下,直接修改表的字符集通常没用。库里的字节没有变,只是解释方式变了,再转一次码反而可能让数据更难恢复。修复前,先在旧库导出的文件里找几条中文,用 file -i 确认原始字节确实是 UTF-8。确认之后,再把数据按原始字节导出,在目标库中用 utf8mb4 重新导入。导入前后各抽样核对几条含中文的记录,逐条比对,不要只看前几行。
新库建议统一使用 utf8mb4。它能存中文,也能完整保存 emoji。应用侧的 JDBC 连接串同样要显式声明字符集,保证读写两端一致。
四、案例三:OSS 下载文件名出现乱码
某教育机构通过 OSS 分享课件,用户下载后文件名显示为一串乱码。这类问题多半出在响应头。HTTP 头部不直接放中文,所以文件名要先做 URL 编码,再通过 Content-Disposition 里的 filename* 参数声明为 UTF-8。以“课件.pdf”为例,写法是 filename*=UTF-8''%E8%AF%BE%E4%BB%B6.pdf。
较老的 IE 版本对 filename* 支持较弱,所以不少项目会同时保留普通的 filename 参数,兼顾旧浏览器。另一种情况是文件上传时名称就已经错了。这时在本地改好文件名后重新上传即可。OSS 中的对象不能直接改名,需要重新上传或复制成新对象。删除旧对象前,先确认外部链接已经不再依赖它。
五、案例四:网页在不同浏览器里表现不一致
一个企业官网部署到 ECS 后,部分页面中文正常,部分却是乱码。检查发现,HTML 文件本身保存为 UTF-8,但 Nginx 没有设置字符集。响应头返回的是默认编码,浏览器于是按另一种编码解析页面。
解决方法是在 Nginx 配置中加入 charset utf-8;,同时在页面头部添加 <meta charset="UTF-8">。两处最好保持一致。浏览器对编码的优先级是:响应头高于页面里的 meta。服务器头写错了,页面里的 meta 救不回来,所以只改页面不改服务器配置,效果有限。
六、排查顺序
- 用一段最简单的中文,例如“测试乱码”,在每一层单独测试,找出第一次出错的环节。
- 用
file -i或编辑器检查文件编码。带 BOM 的 UTF-8 文件在某些程序里会多出不可见字符,遇到奇怪的前缀时先看这一点。 - 对照
SHOW VARIABLES、locale和curl -I的输出,核对服务端、数据库和客户端三方的字符集。 - 修复后保留一份含中文的测试用例,比如一条数据库记录加一个中文文件名,放进发布检查清单,避免下次发布时再次出问题。
七、如何预防
乱码多半是因为缺少统一约定。团队可以在项目初期就把规则写进仓库和运维文档:源文件统一保存为 UTF-8,并在 .editorconfig 中固定 charset = utf-8;数据库创建时默认指定 utf8mb4;接口和页面统一声明 charset;部署文档里写明 locale 要求。规则写清楚,新成员才能照着做,不必每次靠经验补救。
阿里云环境里的字符集支持本身没有问题。多数乱码来自某一层配置没有对齐。从数据经过的第一个环节开始,逐层测试,通常能很快找到问题所在。