近期,为了给一个核心系统减负,组内决定将一些调用量大的查询接口迁移到另一个系统,由于接口逻辑比较复杂,为了保证接口逻辑一致,我们决定将一周内的请求参数在两个接口重放,并用脚本校验两边接口的响应结果。
接口返回数据是json结构的,本想用icdiff、jq来实现,但时间紧迫一时没想出来,同事用python脚本实现了这个对比,但后来又仔细想了想,找出了使用icdiff、jq实现的方法。
对于普通的文本对比,使用diff命令即可完成,但icdiff比diff更好用,对比结果也会更加直观。
- $ text1='{"name":"apple","item_no":2}'
- $ text2='{"name":"a apple","item_no":2}'
- $ icdiff <(echo "$text1") <(echo "$text2")
-
但如果用jq格式化一下再对比,看起来会更加清晰一些。
- $ icdiff <(echo "$text1"|jq .) <(echo "$text2"|jq .)
-
但是有时json数据可能会出现数据一样,但key的顺序不一致的问题,比如:
- $ text1='{"name":"apple","item_no":2}'
- $ text2='{"item_no":2,"name":"apple"}'
- $ icdiff <(echo "$text1"|jq .) <(echo "$text2"|jq .)
-
像对象转json这种操作,是有可能出现不同机器上返回json的key顺序不同的。
好在jq提供了-S选项,可对输出json的key排序,如下:
- $ icdiff <(echo "$text1"|jq -S .) <(echo "$text2"|jq -S .)
-
本以为这样就解决了所有问题,但在脚本运行过程中,我们又发现了新情况,json中的数组项,顺序可能不一致,如下:
- $ text1='{
- "order_id": 121345435624,
- "waybills": [
- {
- "waybill_id": 1,
- "name": "package1",
- "items": [
- {
- "name": "orange",
- "item_no": 1
- },
- {
- "name": "apple",
- "item_no": 2
- }
- ]
- },
- {
- "waybill_id": 2,
- "name": "package2",
- "items": [
- {
- "name": "pear",
- "item_no": 3
- },
- {
- "name": "banana",
- "item_no": 4
- }
- ]
- }
- ]
- }'
- $ text2='{
- "order_id": 121345435624,
- "waybills": [
- {
- "waybill_id": 2,
- "name": "package2",
- "items": [
- {
- "name": "banana",
- "item_no": 4
- },
- {
- "name": "pear",
- "item_no": 3
- }
- ]
- },
- {
- "waybill_id": 1,
- "name": "package1",
- "items": [
- {
- "name": "orange",
- "item_no": 1
- },
- {
- "name": "apple",
- "item_no": 2
- }
- ]
- }
- ]
- }'
- $ icdiff <(echo "$text1"|jq -S .) <(echo "$text2"|jq -S .)
-
因为icdiff没法识别这种顺序区别,它只是逐行进行对比的,虽然两个json逻辑上是一样的,但它区别不出来。
程序中以下情况会造成这种顺序区别:
要解决这种情况还真挺麻烦的,因为需要对json中的数组进行排序,然后再进行对比,之前就是这里想不出来怎么实现。
但在后来,我又仔细的看了看jq的man文档,发现了一个有用的函数walk,然后就试了试,还真发现可以实现。
- $ json_sort='walk(if type == "array" and length >0 then (if .[0].item_no then sort_by(.item_no) elif .[0].waybill_id then sort_by(.waybill_id) else. end) else . end)'
- $ icdiff <(echo "$text1"|jq -S "$json_sort") <(echo "$text2"|jq -S "$json_sort")
-
Linux命令结合起来,总能产生更大的作用,当然这也需要付出一些折腾时间啊。