中文乱码UTF-8SSE故障排查

AI API 中文乱码怎么解决?UTF-8、SSE 与 JSON 编码排查指南

2026-09-13 · 约 9 分钟阅读

AI API 返回英文正常、中文却出现问号、方框、\u4f60,或者流式输出偶尔出现替换字符,通常不是模型“不会中文”,而是字节在 HTTP、中转代理、SDK、SSE 解析、日志或数据库某一层被错误解码。乱码问题最容易被误判,因为开发者看到的是最终页面,却不知道错误第一次出现在哪里。

高效排查的原则是:保存原始字节和响应头,从上游向页面逐层比较,不要一上来就在前端做字符串替换。

先分清四类现象

  • 风格文本:可能只是 JSON 转义尚未解析,并非乱码
  • � 替换字符:UTF-8 字节序列被截断或以错误边界解码
  • 你好 一类字符:UTF-8 字节被当作其他单字节编码解释
  • 数据库读出问号:写入、列字符集、连接字符集或导出环节发生损失

先记录一个最小测试词,例如“中文测试🚀”,同时包含汉字和多字节 emoji。若只测试 ASCII,编码错误可能完全不会暴露。

第一步:直接检查上游原始响应

绕过应用前端,用 curl 保存响应头和正文:

curl -N -D headers.txt \
  -H "Authorization: Bearer $AI_API_KEY" \
  -H "Content-Type: application/json; charset=utf-8" \
  "$AI_BASE_URL/chat/completions" \
  --data '{"model":"your-model","messages":[{"role":"user","content":"只回复:中文测试🚀"}]}' \
  -o body.bin

如果 body.bin 已经异常,继续比较中转地址与可用的直接上游测试,并向服务商提交 request ID、时间、响应头和十六进制片段。若文件正常而页面乱码,问题就在自己的服务端或前端链路。

注意不要把真实 Key、完整用户 Prompt 或敏感响应贴到工单和公开群里。

第二步:流式响应必须增量解码

UTF-8 中一个字符可能由多个字节组成,而网络 chunk 边界不保证落在字符边界上。错误写法是对每个二进制 chunk 单独调用一次解码;当一个汉字被拆到两个 chunk 时,解码器会产生替换字符。

Node/浏览器端应复用同一个 TextDecoder 并开启流模式:

const reader = response.body!.getReader();
const decoder = new TextDecoder("utf-8");
let pending = "";
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  pending += decoder.decode(value, { stream: true });
  const events = pending.split("\n\n");
  pending = events.pop() ?? "";
  for (const event of events) {
    parseSseEvent(event);
  }
}
pending += decoder.decode();

最后一次无参数 decode() 用于冲刷解码器内部残留。与此同时,SSE 事件也可能跨 chunk,因此还需要 pending 保存未完成事件。仅修复字符边界、不修复事件边界,仍会出现随机 JSON 解析失败。

第三步:区分 JSON 转义与双重序列化

JSON.parse('"\\u4f60\\u597d"') 得到的是正常“你好”。如果页面直接展示反斜杠,常见原因是响应被序列化了两次:上游 JSON 字符串先被 JSON.stringify,外层接口又序列化一次。

修复方法不是全局替换 \u,因为用户原文可能真的包含转义示例。应该在明确的协议层只解析一次,并用类型验证保证 content 最终是字符串,而非“包含 JSON 的字符串”。

第四步:检查代理是否改写响应

中转层或反向代理应尽量透传正文,不要把流式响应先按文本读取再重新拼接。检查 Content-Type 是否符合实际响应,压缩是否被重复处理,以及代理是否在 SSE 中插入调试文本。对于流式接口,缓存与内容转换通常应关闭,缓冲策略也要单独配置。

如果只有经过某个节点才乱码,可使用相同请求体逐跳比较哈希或十六进制数据。这样能把“可能是网络”缩小为具体一跳。

第五步:数据库和消息队列也要验收

页面即时显示正常,但刷新历史会话后乱码,说明错误发生在持久化阶段。验证写入前字符串、数据库连接设置、字段类型、读取结果和 JSON 导出。emoji 是很好的探针,因为有些配置能保存常用汉字,却无法完整保存更广字符范围。

消息队列也可能通过错误的默认字符集转换正文。更稳妥的做法是消息体统一 UTF-8 JSON,并在元数据中明确内容类型,而不是依赖运行环境默认值。

不要忽略日志系统

终端显示乱码不一定代表业务数据已损坏,也可能只是日志查看器解码错误。把同一请求的原始响应、服务端变量、数据库读取值和浏览器 Network 内容放在一起比较。日志中应记录 request ID 与字节长度,但避免记录完整敏感文本。

最小回归测试集

上线前至少覆盖:纯中文、中英混排、emoji、组合字符、代码块、反斜杠转义,以及每个字节单独到达的极端流式分片。再分别测试官方直连和候选中转站,以区分应用缺陷与线路兼容性问题。

总结

AI API 中文乱码通常可沿“原始字节—HTTP—增量解码—SSE—JSON—存储—页面”逐层定位。最关键的修复是保持 UTF-8 一致、复用流式解码器、缓存未完成事件,并避免双重序列化。若问题只在特定中转线路出现,可前往 openairouter.net 查看 AI API 中转站对比与排行榜,选择候选平台后用本文测试集逐一验收。

找到最适合你的 AI API 中转站

收录 125+ 服务商,按价格、模型、标签一键筛选

查看所有中转站 →