中文為什麼變成 \u4e2d\u6587
結論:\u4e2d\u6587 是合法的 Unicode 轉義,不是編碼錯誤。真正的亂碼是「测试」這種。分清楚兩者,才知道該改序列化設定還是改檔案編碼。

結論:看到 \uXXXX 先當作正常轉義,用 JSON.parse 試一次就能確認能否還原;要直接顯示漢字就關掉序列化端的純 ASCII 輸出(例如 ensure_ascii=False),只有傳輸通道不支援非 ASCII 時才保留轉義。
因為它被轉義了,不是壞了。
JSON.parse('"\\u4e2d\\u6587"') // "中文"
\u4e2d 就是「中」,\u6587 是「文」。這兩串字元是 JSON 字串裡的合法轉義序列,解析器讀到就會還原。功能上不會出錯,只是日誌、抓包、程式碼評閱裡讀起來很痛苦。
誰在轉義
| 工具 | 預設行為 | 開關 |
|---|---|---|
Python json.dumps |
轉義(ensure_ascii=True) |
ensure_ascii=False |
JavaScript JSON.stringify |
不轉義 | 無 |
| Java Jackson | 不轉義 | 可選開啟 |
PHP json_encode |
不轉義(5.4+) | — |
Go encoding/json |
不轉義 | 無 |
Python 是最高頻的來源。預設值有歷史原因:保證輸出是純 ASCII,任何環境都能安全傳輸,代價就是中文全變轉義串。
轉義 vs 亂碼,先分清楚
轉義:\u4e2d\u6587,形如 \uXXXX,每個漢字六個字元。原因:序列化設定。
亂碼:测试、涓枃。原因:位元組按 UTF-8 寫入,卻按 Latin-1 或 GBK 讀取。
判斷方法:把文字複製到瀏覽器主控台執行 JSON.parse('"貼上內容"'),能還原成正常中文就是轉義,還原不出來或直接報錯,就是編碼問題。亂碼的修法完全不同——要統一讀寫兩端的編碼。
想直接看到漢字
json.dumps(data, ensure_ascii=False)
改完記得確認下游沒問題:有些舊系統真的依賴純 ASCII 傳輸,尤其是走簡訊、郵件、舊版閘道的場景。
什麼時候該保留轉義
- 傳輸通道對非 ASCII 不友善(舊版 HTTP 標頭、部分簡訊閘道)
- 需要把 JSON 嵌進另一層 JSON 字串裡,轉義能少一層引號衝突
- 日誌系統按位元組截斷,多位元組字元被切斷會產生非法序列
除此之外,可讀性優先,關掉轉義。
常見問題
為什麼 Python 預設會把中文轉成 \uXXXX?
因為 ensure_ascii=True 是預設值,保證輸出是純 ASCII,任何環境都能安全傳輸。代價是每個非 ASCII 字元變成六個字元。
要不要關掉 ensure_ascii?
可讀性優先時關掉。改完再確認下游:舊版 HTTP 標頭、部分簡訊閘道、按位元組截斷的日誌系統仍可能依賴純 ASCII。
傳輸通道不支援非 ASCII 時是否該保留轉義?
要。把 JSON 嵌進另一層 JSON 字串,或走對非 ASCII 不友善的通道時,轉義能減少引號衝突,也能避免多位元組字元被截斷。