← 全部文章

如何壓縮 JSON —— 以及什麼時候該做

壓縮 JSON 會移除所有不必要的空白以縮小體積、加快 API 回應。學習在 JavaScript、Python、命令列與瀏覽器中壓縮 JSON —— 以及什麼時候不必折騰。

JSON 在設計上對空白字元寬容。JSON 美化器 把緊湊、機器生成的字串展開成有縮排、便於人類閱讀的輸出。JSON 壓縮器 則完全相反 —— 把那些空白全部剝除以縮小檔案體積。兩種操作都不會改動資料本身,只改變空白。本指南說明何時要美化、何時要壓縮,以及如何進行這兩件事 —— 在 JavaScript、Python、命令列,以及直接在你的瀏覽器中。

壓縮 JSON 究竟做了什麼

看看這份格式化過的 JSON 物件:

{
  "user": {
    "id": 42,
    "name": "Alice",
    "roles": [
      "admin",
      "editor"
    ],
    "active": true
  }
}

壓縮之後:

{"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

兩個字串在語意上完全相同。任何 JSON 解析器都會把它們當作相同資料。壓縮後的版本是 73 個字元;格式化版本是 110 個。這是 34% 的縮減 —— 而 JSON 越大、巢狀越深,差距越大。

會被移除的: 所有換行、所有縮排的空格與定位點,鍵與值之間 : 前後的空格,以及項目之間 , 之後的空格。

永遠不會被移除的: 字串值內部 的空白("hello world" 仍然是 "hello world"),以及真正的資料:鍵、值與結構字元。

相反操作:什麼是 JSON 美化器?

JSON 美化器 —— 也叫 JSON 格式化器或 JSON pretty-printer —— 做的事和壓縮器相反。它把緊湊、難讀的 JSON 展開,加上一致的縮排與換行,讓結構對人類讀者一目了然。

在這個脈絡中,「beautify」、「format」、「pretty-print」與「indent」所指的是同一件事。輸出與輸入在語意上一致,只有空白不同。

// 壓縮(你從 API 或日誌收到的樣子)
{"order":{"id":1001,"items":[{"sku":"A1","qty":2},{"sku":"B3","qty":1}],"total":49.99}}

// 美化(2 空格縮排)
{
  "order": {
    "id": 1001,
    "items": [
      { "sku": "A1", "qty": 2 },
      { "sku": "B3", "qty": 1 }
    ],
    "total": 49.99
  }
}

什麼時候要美化 JSON

最常見的情境與壓縮相反:你收到緊湊的 JSON —— 來自 API 回應、日誌、資料庫匯出或同事的訊息 —— 而你需要閱讀或編輯它。

  • 除錯 API 回應 —— 壓縮過的回應幾乎無法掃讀;美化只要一秒就能讓每個鍵都可見
  • 編輯設定檔 —— 把變更提交到 JSON 設定前先美化,diff 才會易讀,審閱者才能跟上變化
  • 記錄資料結構 —— 在 README、wiki 或 PR 描述中的美化 JSON 遠比單行更能表達結構
  • 檢視陌生資料 —— 面對新 API 或從沒見過的資料集時,先美化能讓你立刻看清形狀
  • 修復壞掉的 JSON —— 美化還會順便驗證 JSON;若輸出看起來不對或出現錯誤,代表輸入有語法問題

如何用 fixjson 美化 JSON

fixjson 的 JSON 美化器 同時處理合法與損壞的 JSON —— 這是大多數格式化器做不到的。使用方法:

  1. 貼上你的 JSON 到左邊的輸入面板。它可以是壓縮的、部分格式化的,甚至是壞的(尾隨逗號、單引號、未加引號的鍵 —— 都接受)。
  2. 輸出立刻出現 在右邊,以 2 空格縮排美化好。不需要按按鈕 —— 工具會在你輸入時即時更新。
  3. 依需要調整縮排。縮排選擇器可以在 2 空格、4 空格與定位點之間切換,以符合你專案的風格指南。
  4. 複製結果,用輸出面板標頭的複製按鈕,或者全選直接貼上。

若你的 JSON 有錯誤,fixjson 會在美化前自動修復 —— 尾隨逗號被移除、單引號被換成雙引號、缺少的括號被補齊。這代表你可以貼上 LLM、Python REPL 或日誌檔的原始輸出,拿回乾淨、格式化的 JSON,而不必先手動修錯。

一切都在你的瀏覽器中執行。任何資料都不會被傳送到伺服器 —— 當 JSON 包含 API 金鑰、使用者資料或其他敏感資訊時,這點尤其重要。

在程式碼中美化 JSON

當你不是在瀏覽器中,而是要以程式方式產生美化輸出時,JSON.stringify 的第三個引數控制縮排:

// 2 空格縮排
JSON.stringify(data, null, 2);

// 4 空格縮排
JSON.stringify(data, null, 4);

// 定位點縮排
JSON.stringify(data, null, '\t');

在 Python 中:

import json

# 2 空格縮排,鍵已排序
print(json.dumps(data, indent=2, sort_keys=True))

在命令列用 jq(預設輸出本身就是美化的):

jq . data.min.json

如何在 JavaScript 中壓縮 JSON

JavaScript 內建的 JSON.stringify 在省略第三個引數(spacer)時就會輸出壓縮 JSON。

從 JavaScript 物件出發

const data = {
  user: {
    id: 42,
    name: "Alice",
    roles: ["admin", "editor"],
    active: true
  }
};

const minified = JSON.stringify(data);
// {"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

不需要任何函式庫。JSON.stringify(value) 永遠輸出緊湊內容。

從 JSON 字串出發(parse 後再 stringify)

如果你手上是一段格式化的 JSON 字串,想要把它壓縮:

const formatted = `{
  "user": {
    "id": 42,
    "name": "Alice"
  }
}`;

const minified = JSON.stringify(JSON.parse(formatted));
// {"user":{"id":42,"name":"Alice"}}

這趟往返 —— parse 後不帶 spacer 再 stringify —— 是標準作法。它有個有用的副作用:JSON.parse 若輸入不合法就會丟錯,壞掉的 JSON 在你嘗試傳送之前就會被攔下。

在 Node.js 中從檔案讀取

import { readFileSync, writeFileSync } from 'fs';

const input = readFileSync('data.json', 'utf8');
const minified = JSON.stringify(JSON.parse(input));
writeFileSync('data.min.json', minified);

如何在 Python 中壓縮 JSON

Python 的 json 模組只要兩個引數傳給 json.dumps 就能乾淨地處理。

從 Python dict 出發

import json

data = {
    "user": {
        "id": 42,
        "name": "Alice",
        "roles": ["admin", "editor"],
        "active": True
    }
}

minified = json.dumps(data, separators=(',', ':'))
# {"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

關鍵是 separators=(',', ':') 引數。預設情況下,json.dumps 使用 ', '': '(尾端帶空格)。傳入 (',', ':') 就能完全去掉那些空格。

從 JSON 檔案出發

import json

with open('data.json', 'r') as f:
    data = json.load(f)

with open('data.min.json', 'w') as f:
    json.dump(data, f, separators=(',', ':'))

如何在命令列壓縮 JSON

使用 jq

jq 是 Unix-like 系統上事實上的 JSON 處理器。-c 旗標會產出緊湊(壓縮)輸出:

jq -c . data.json > data.min.json

# 行內
echo '{ "name": "Alice", "age": 30 }' | jq -c .
# {"name":"Alice","age":30}

用 Python(不需要額外安裝)

若沒有 jq,Python 幾乎總是有的:

python3 -m json.tool --compact data.json > data.min.json

--compact 旗標是在 Python 3.9 才加入的。較舊版本:

python3 -c "import json,sys; print(json.dumps(json.load(sys.stdin), separators=(',',':')))" < data.json

如何線上壓縮 JSON

對一次性任務 —— 提交前要處理的設定檔、要複製到別處的 API 回應 —— 瀏覽器型工具比任何命令列設定更快。一個好的線上 JSON 壓縮器應該接受貼上或檔案上傳、在用戶端即時壓縮,而且絕不把資料傳到伺服器。

fixjson 的 JSON 壓縮器 把所有處理都放在本機。貼上 JSON,點 Minify,然後複製結果 —— 不會有任何東西離開你的瀏覽器。

壓縮 JSON 實際能省多少?

節省多少取決於原本的格式化方式。

  • 輕度格式化(2 空格縮排、淺巢狀):典型節省 15–25%
  • 重度格式化(4 空格縮排、深巢狀、鍵多):典型節省 30–50%
  • 已經緊湊(已壓縮或機器生成):節省接近 0%

實務範例 —— 一個列出 100 個使用者物件的 REST API 回應:

格式大小
美化(2 空格)24.8 KB
壓縮16.1 KB
壓縮 + gzip3.2 KB

請注意 gzip 那一列。這是本指南中最重要的觀察 —— 也直接帶出下一個問題。

Minification 與 Compression:差別在哪?

Minification 去掉空白字元 —— 在資料層級上是無損的,並產出較小的文字字串。Compression(gzip、Brotli、zstd)用演算法在整個檔案中尋找重複的位元組樣式並以更有效率的方式表示。它在位元組層級上運作,輸出在不解壓的情況下無法閱讀。

實際影響: 當你的伺服器啟用 HTTP 壓縮 —— 任何 JSON API 都應該啟用 —— gzip 或 Brotli 會把空白壓得跟其他內容一樣狠。先 minify 再壓縮通常只能在既有壓縮之上再省下邊際的一點(3–8%)。

這把決策重新定義為:

  • 若伺服器使用 HTTP 壓縮:minification 只是次要的最佳化
  • 若在磁碟或資料庫中儲存 JSON 且沒有壓縮:minification 能顯著降低儲存成本
  • 若要傳給不支援 HTTP 壓縮的用戶端:minification 更重要

實務中的壓縮:HTTP/2、HTTP/3 以及要檢查什麼

較新的 HTTP 版本並不改變算術 —— 壓縮仍然發生在回應主體層級 —— 但在決定是否要 minify 時,有幾個標頭值得檢查:

  • Content-Encoding: gzip(或代表 Brotli 的 br,或是 zstd 在某些部署中)—— 確認傳輸中的主體已被壓縮。
  • Vary: Accept-Encoding —— 必備,讓 CDN 能分別快取壓縮與未壓縮的回應。
  • HTTP/2 / HTTP/3 標頭壓縮(HPACK / QPACK) —— 壓縮的是 標頭,而不是主體。它無法取代 JSON 負載的 gzip/brotli。

若你的 CDN 已用 br 提供服務,minify 只能再省幾個百分點。若你維護的某個服務不做壓縮(自訂二進位、webhook 目標、IoT 端點),minification 仍有幫助。

對大型 JSON 改用串流而不是 minify

對真正大型的負載 —— 數 MB 的 API 回應、日誌轉儲、資料集匯出 —— 正確做法通常不是去壓縮整塊,而是串流它。兩種模式:

  • NDJSON / JSON Lines —— 每行一個 JSON 值。用戶端可以在每一行抵達時就解析與處理,而不必等到整份文件。
  • 分塊串流解析器 —— 像 clarinet / jsonparse 等函式庫會在資料從網路抵達時就處理 token,這正是記憶體受限環境想要的。

什麼時候應該 minify JSON

生產環境的 API 回應(未啟用 HTTP 壓縮)

若你的 API 伺服器沒啟用 Content-Encoding: gzipContent-Encoding: br,每個空白位元組都會被傳輸。Minify 能縮小負載並加快回應,在慢速行動連線上尤其明顯。

內嵌於 HTML 中的 JSON

嵌在 <script type="application/json"> 標籤裡或直接寫在 HTML 中的 JSON 是頁面總重量的一部分。Minify 它能讓首屏載入更小。

大規模儲存的 JSON 檔案

若你在資料倉儲、物件儲存或資料庫中存放數百萬筆 JSON 紀錄,而儲存層沒有壓縮 —— 那些空白會累積。在 1000 萬筆紀錄上省 30% 相當可觀。

有大小限制的邊界情境

某些系統有硬性大小限制:webhook payload、特定訊息佇列、cookie 值、URL 參數。若你的 JSON 已接近上限,minify 可能是留在限制內最簡單的做法。

建置產物與打包的設定

前端建置中打包的 JSON 設定檔會增加 bundle 體積。把它作為建置步驟的一部分 minify —— 就像 JS、CSS 一樣 —— 是標準做法。

什麼時候大概不必折騰

伺服器已經在做 HTTP 壓縮

檢查你的回應標頭。若看到 Content-Encoding: gzipContent-Encoding: br,代表伺服器已經在傳輸中壓縮 JSON。在此之上 minify 最多再省幾個百分點 —— 通常不值得額外複雜度。

JSON 是給人讀的

開發者編輯的設定檔、除錯日誌、需要人工審閱的匯出資料 —— 這些更需要可讀性而不是緊湊。永遠不要 minify 給人經常閱讀的 JSON。

資料本來就很小

對 1 KB 以下的 JSON,minify 與格式化版本之間的絕對差距通常不到 300 位元組。在這個規模上,HTTP 請求本身的負擔才是主因;在主體上削減 200 位元組對效能毫無可量測影響。

會讓除錯變難

日誌、錯誤訊息與監控系統中的 minified JSON 難以掃讀。如果你需要在生產中讀 JSON 輸出,就保持格式化。

建置流水線中的壓縮

一個在 Node.js 建置流水線中壓縮 JSON 設定檔的實用方案:

// scripts/minify-configs.js
import { readdirSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';

const configDir = './config';
const outputDir = './dist/config';

for (const file of readdirSync(configDir)) {
  if (!file.endsWith('.json')) continue;
  const raw = readFileSync(join(configDir, file), 'utf8');
  const minified = JSON.stringify(JSON.parse(raw));
  writeFileSync(join(outputDir, file), minified);
  const saved = raw.length - minified.length;
  console.log(`${file}: ${raw.length} → ${minified.length} bytes (saved ${saved})`);
}

把它放在部署前的步驟執行。若有設定檔包含不合法的 JSON,JSON.parse 會丟錯,建置就會失敗 —— 這正是你要的。

壓縮 JSON 常見的錯誤

把壓縮當作混淆

壓縮後的 JSON 在任何有意義的層次上都沒有被隱藏。任何人都可以幾秒鐘內把它丟進 格式化器 把一切讀出來。不要 minify 敏感資料後就以為大功告成 —— 用真正的加密,或乾脆不要傳送敏感資料。

忘了 Python 的編碼選項

json.dumps 預設輸出是 ASCII 安全的,會把非 ASCII 字元轉義成 \uXXXX。若要原樣保留 UTF-8 字元,傳入 ensure_ascii=False:

minified = json.dumps(data, separators=(',', ':'), ensure_ascii=False)

大整數失準

對含有非常大整數的 JSON 進行 parse 後再 stringify,某些語言可能會失準。JavaScript 的 JSON.parse 會把所有數字轉成 IEEE 754 雙精度浮點,無法精確表示 2⁵³ 以上的整數。若你的 JSON 含有大整數(像是資料庫 ID 或外部服務 ID),請確認 parse-stringify 不會損害它們。

常見問題

怎麼在 JavaScript 中壓縮 JSON?

呼叫 JSON.stringify(value) 不要帶第三個引數 —— 輸出總是緊湊的。要壓縮現有字串,做一次往返:JSON.stringify(JSON.parse(formatted))

壓縮 JSON 可以省下很多檔案大小嗎?

壓縮前通常是 15–50%,取決於縮排與巢狀深度。但若伺服器已經送出 Content-Encoding: gzipbr,gzip 本來就會把空白壓掉,先 minify 只能多省一點點。

壓縮(minify)與壓縮(compress)JSON 的差別?

Minify 去掉空白並保留人類可讀的文字;compression(gzip、Brotli)會重新編碼位元組,必須解壓才能讀。兩者可以疊用,但在傳輸過程中,大部分工作由 compression 完成。

壓縮和格式化有什麼不同?

兩者相反:壓縮去掉空白以縮小體積,格式化加入空白以提升可讀性。反向操作請見 如何格式化 JSON

結語

壓縮 JSON 是最簡單的最佳化之一 —— 在任何語言裡只是一次函式呼叫,在任何瀏覽器工具裡只是一次點擊。合適的時機是:在沒有 HTTP 壓縮的情況下傳輸 JSON、在沒有儲存層壓縮的情況下大規模儲存 JSON,或將它打包進建置產物。

不該做的時機是:JSON 是要給人讀的、負載本來就小,或你的基礎設施已經在傳輸中壓縮回應。

當你確實需要 minify 時 —— 不論是在建置腳本、CI 步驟,或一次性整理 —— 各語言的做法都一樣:先解析 JSON,再不帶 spacer 把它序列化。如果 JSON 有錯誤導致無法解析,請先 修復它,再進行壓縮。