alltools.one
JSON
2025-06-24
7 min
alltools.one Team
JSONDiffDebuggingAPITesting

JSON Diff 除錯指南:在複雜資料中找出變更

標準的文字差異比較工具在處理 JSON 時會遇到困難。鍵值重新排序、空白變更和深層巢狀會產生雜訊,掩蓋了實際的資料變更。結構化 JSON 差異比較的是語義——實際資料——而非文字表示。本指南涵蓋有效的 JSON 比較和除錯技術。

為什麼標準差異比較對 JSON 無效

考慮兩個語義上相同的 JSON 物件:

版本 A:

{"name":"Alice","age":30,"roles":["admin","editor"]}

版本 B:

{
  "age": 30,
  "name": "Alice",
  "roles": ["admin", "editor"]
}

文字差異比較會顯示每一行都有變更,但資料是完全相同的。結構化差異比較能識別它們是一樣的。

再考慮一個實際的變更:

// Before
{ "user": { "name": "Alice", "permissions": ["read", "write", "admin"] } }

// After
{ "user": { "name": "Alice", "permissions": ["read", "write"] } }

結構化差異比較會報告:removed user.permissions[2]: "admin" ——這正是你需要的資訊。

使用我們的 JSON Diff 工具立即試試。

JSON 變更的類型

結構化 JSON 差異比較將變更分為以下類別:

變更類型範例
新增新的鍵或陣列元素
移除缺少的鍵或陣列元素
修改現有鍵的值已變更
類型變更值的類型已變更(string → number)
移動陣列元素重新排序

命令列 JSON 差異比較

使用 jq 快速比較

# Sort keys and compare
diff <(jq -S . before.json) <(jq -S . after.json)

# Compare specific paths
diff <(jq '.config.database' before.json) <(jq '.config.database' after.json)

專用工具

# json-diff (npm)
npx json-diff before.json after.json

# Output:
# {
#   "user": {
#     "permissions": [
#       "read",
#       "write",
#-      "admin"
#     ]
#   }
# }

# jd (Go)
jd before.json after.json

除錯 API 回應變更

當 API 回應出現非預期的變更時,系統化的比較有助於找出根本原因:

步驟 1:擷取基準

儲存一個已知正確的回應:

curl -s https://api.example.com/users/123 | jq -S . > baseline.json

步驟 2:擷取當前版本

curl -s https://api.example.com/users/123 | jq -S . > current.json

步驟 3:結構化差異比較

# Human-readable
npx json-diff baseline.json current.json

# Machine-readable (JSON Patch format)
npx json-diff baseline.json current.json --json

步驟 4:過濾雜訊

排除每次請求都會變更的欄位(時間戳、請求 ID):

# Remove volatile fields before comparing
jq 'del(.meta.requestId, .meta.timestamp)' response.json

JSON Patch (RFC 6902)

JSON Patch 是一種標準化格式,用於描述對 JSON 文件的變更:

[
  { "op": "replace", "path": "/user/name", "value": "Bob" },
  { "op": "remove", "path": "/user/permissions/2" },
  { "op": "add", "path": "/user/email", "value": "bob@example.com" }
]

操作:

  • add:新增一個值
  • remove:移除一個值
  • replace:變更一個現有值
  • move:將一個值移動到新路徑
  • copy:將一個值複製到新路徑
  • test:驗證一個值是否存在(用於條件式修補)

JSON Patch 適合向 API 發送增量更新,而非替換整個文件。

設定檔漂移偵測

追蹤設定檔隨時間的變更:

#!/bin/bash
# drift-check.sh
BASELINE="config-baseline.json"
CURRENT="config-current.json"

DIFF=$(npx json-diff "$BASELINE" "$CURRENT" 2>/dev/null)

if [ -n "$DIFF" ]; then
  echo "Configuration drift detected:"
  echo "$DIFF"
  exit 1
fi

echo "No drift detected."

在測試中使用 JSON 差異比較

在測試中使用結構化比較來驗證 API 回應:

const { diff } = require('json-diff');

test('API response matches expected structure', async () => {
  const response = await fetch('/api/users/123');
  const data = await response.json();
  
  const expected = {
    id: 123,
    name: 'Alice',
    role: 'admin'
  };
  
  const changes = diff(expected, data);
  expect(changes).toBeUndefined(); // undefined means identical
});

處理大型 JSON 檔案

對於數百萬位元組的 JSON 檔案,視覺化差異比較變得不切實際:

  1. 先查詢:在進行差異比較之前,使用 JSONPath 提取相關部分。請參閱我們的 JSONPath 指南
  2. 摘要模式:按類型計算變更數量,而非顯示每一個變更
  3. 串流差異比較jd 等工具透過串流高效處理大型檔案
# Extract and compare a specific section
jq '.data.users[:10]' large-before.json > section-before.json
jq '.data.users[:10]' large-after.json > section-after.json
npx json-diff section-before.json section-after.json

常見問題

我應該使用 JSON Patch 還是 JSON Merge Patch?

JSON Patch(RFC 6902)使用操作陣列,可以表達任何變更,包括陣列元素操作。JSON Merge Patch(RFC 7396)更簡單——你發送一個部分 JSON 物件,它會與目標合併。簡單的物件更新使用 Merge Patch;需要陣列操作或原子操作時使用 JSON Patch。

如何對不同鍵順序的 JSON 進行差異比較?

大多數結構化 JSON 差異比較工具將鍵的順序視為不重要——{"a":1,"b":2} 等於 {"b":2,"a":1}。對於基於文字的工具,先使用 jq -S . 進行標準化,它會按字母順序排列鍵。我們的 JSON Diff 工具會自動處理鍵的排序。

相關資源

Published on 2025-06-24
JSON Diff Debugging Guide: Find Changes in Complex Data | alltools.one