如何用Python或Go为元素顺序不同的嵌套JSON生成相同哈希值
实现无序嵌套JSON的一致哈希生成
要让元素顺序不同但内容等价的嵌套JSON生成相同哈希,核心是先标准化JSON结构——递归排序所有字典的键,对数组元素先标准化再排序,确保等价结构的序列化结果完全一致,最后对序列化内容计算哈希。以下是Python和Go的具体实现:
Python 实现
步骤说明
- 解析JSON为Python原生数据结构(dict/list)
- 递归标准化:
- 对字典:按键名排序后重新构建
- 对列表:先标准化每个元素,再对元素进行排序(通过将元素转为可哈希的元组实现)
- 将标准化后的结构序列化为固定格式的JSON字符串
- 对字符串计算哈希(示例用SHA256,可替换为MD5等)
代码示例
import json import hashlib def normalize(data): if isinstance(data, dict): # 排序字典的键,递归标准化每个值 return sorted((k, normalize(v)) for k, v in data.items()) elif isinstance(data, list): # 先标准化每个列表元素,再对元素排序 normalized_elements = [normalize(item) for item in data] # 嵌套结构转为元组才能排序 return sorted(tuple(item) if isinstance(item, list) else item for item in normalized_elements) else: # 基本类型直接返回 return data def get_consistent_hash(json_str): # 解析JSON data = json.loads(json_str) # 标准化结构 normalized_data = normalize(data) # 序列化为JSON字符串,确保格式一致 serialized = json.dumps(normalized_data, sort_keys=True) # 计算SHA256哈希 return hashlib.sha256(serialized.encode('utf-8')).hexdigest() # 测试示例 json1 = '''{ "X":{ "Y":[ { "A":"1", "B":{ "b1":"2", "b2":"2" } }, { "C":"4", "D":{ "d1":"5", "d2":"6" } } ], "Z":[ { "E":{ "e1":"7", "e2":"8" }, "F":"9" } ] } }''' json2 = '''{ "X":{ "Y":[ { "C":"4", "D":{ "d1":"5", "d2":"6" } }, { "A":"1", "B":{ "b1":"2", "b2":"2" } } ], "Z":[ { "E":{ "e1":"7", "e2":"8" }, "F":"9" } ] } }''' print(get_consistent_hash(json1)) print(get_consistent_hash(json2)) # 输出两个完全相同的哈希值
Go 实现
步骤说明
- 解析JSON为
interface{}类型 - 递归标准化:
- 对
map[string]interface{}:按键名排序后重新构建map - 对
[]interface{}:先标准化每个元素,再通过自定义排序规则对slice排序(将元素转为JSON字符串后比较)
- 对
- 将标准化后的结构序列化为JSON字节数组(Go的
json.Marshal默认会对map键排序) - 对字节数组计算哈希
代码示例
package main import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "sort" "strings" ) func normalize(data interface{}) interface{} { switch v := data.(type) { case map[string]interface{}: // 提取并排序map的键 keys := make([]string, 0, len(v)) for k := range v { keys = append(keys, k) } sort.Strings(keys) // 按排序后的键重新构建map,递归标准化每个值 sortedMap := make(map[string]interface{}) for _, k := range keys { sortedMap[k] = normalize(v[k]) } return sortedMap case []interface{}: // 先标准化每个列表元素 normalizedElements := make([]interface{}, len(v)) for i, item := range v { normalizedElements[i] = normalize(item) } // 自定义排序:将元素转为JSON字符串后比较 sort.Slice(normalizedElements, func(i, j int) bool { iBytes, _ := json.Marshal(normalizedElements[i]) jBytes, _ := json.Marshal(normalizedElements[j]) return strings.Compare(string(iBytes), string(jBytes)) < 0 }) return normalizedElements default: // 基本类型直接返回 return v } } func getConsistentHash(jsonStr string) (string, error) { var data interface{} // 解析JSON if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { return "", err } // 标准化结构 normalizedData := normalize(data) // 序列化为JSON字节数组 serialized, err := json.Marshal(normalizedData) if err != nil { return "", err } // 计算SHA256哈希 hash := sha256.Sum256(serialized) return hex.EncodeToString(hash[:]), nil } func main() { json1 := `{ "X":{ "Y":[ { "A":"1", "B":{ "b1":"2", "b2":"2" } }, { "C":"4", "D":{ "d1":"5", "d2":"6" } } ], "Z":[ { "E":{ "e1":"7", "e2":"8" }, "F":"9" } ] } }` json2 := `{ "X":{ "Y":[ { "C":"4", "D":{ "d1":"5", "d2":"6" } }, { "A":"1", "B":{ "b1":"2", "b2":"2" } } ], "Z":[ { "E":{ "e1":"7", "e2":"8" }, "F":"9" } ] } }` hash1, err := getConsistentHash(json1) if err != nil { fmt.Println("Error:", err) return } hash2, err := getConsistentHash(json2) if err != nil { fmt.Println("Error:", err) return } fmt.Println(hash1) fmt.Println(hash2) // 输出两个完全相同的哈希值 }
内容的提问来源于stack exchange,提问作者Sahil Sangani
相关产品推荐
相关产品推荐

