上周查一个接口的返回值,响应体接近五万字,全部压在一行里。我要找的字段叫 "shop_name",用编辑器的查找功能敲进去,光标跳到了第 3 万个字符附近,但我看不见它在哪个对象里、是第几条记录,也不敢确认命中的是键名还是某个同名的值。那次之后我给自己定了个规矩:读 JSON 先让它变成结构,再谈找东西。
格式化只解决"撑开",不解决"在哪"
把一行拆成缩进多行,是很多人的第一步。这一步确实有用,可读性立刻上来了。但它给不了你层级感:缩进 12 层的文件靠肉眼数空格是低效的,而且展开之后行数从 1 行变成几千行,滚动反而更慢。
我现在的做法是直接把数据丢进 JSON视图。每个对象和数组变成一个可折叠的节点,展开或收起来都行,也能全部展开、全部收缩。找字段这件事的本质就变了:不再是"扫过多少行文字",而是"在哪些分支里搜"。
类型颜色是我用得最多的第二个信息。字符串、数字、布尔值、null 各用不同颜色区分,扫一眼就知道 "total": 20 是数字,"total": "20" 是字符串——这两者在接口里长得一样,出问题时行为完全不同。我在一次联调里被 "status": null 和 "status": "" 折腾过很久,从那以后先看颜色再读值。
路径写法:层级、键名、数组下标
嵌套结构要有名字才能沟通。我的习惯是对象层级用点,数组用方括号下标,下标从 0 开始。这样一个字段的位置就能写成一条完整路径,说给别人听、贴进代码、写进工单都是同一串字符。
举个具体的结构:
{
"code": 0,
"data": {
"list": [
{ "id": 101, "items": [ { "sku": "A-1", "name": "杯子" }, { "sku": "A-2", "name": "壶" }, { "sku": "A-3", "name": "盘" } ] },
{ "id": 102, "items": [ { "sku": "B-1", "name": "锅" } ] }
],
"page": { "no": 1, "size": 20, "has_more": false }
}
}
| 路径写法 | 指向什么 | 容易踩的点 |
|---|---|---|
data.page.size |
数字 20 | 键名重复时只有一条路径是对的 |
data.list[0].items[2].name |
字符串 "盘" | 下标从 0 数,第 3 条写成 [2] |
data.list[1].items[0].sku |
字符串 "B-1" | 数组只有一条时也可能被当成对象 |
data.list[0].items |
整个数组,3 个元素 | 折叠时看着像空节点,其实有内容 |
在树里点任意节点就能复制它的路径,这一点替我省了大量手工抄写的功夫。手工抄路径的错法很典型:下标写偏一位,测试时对着错的对象查,最后以为接口没返回。
折叠、搜索、复制路径,这三件事我分别什么时候用
搜索按关键字匹配,键名和值都能命中,命中的地方会高亮,还能上一个、下一个地跳。我要判断"这个字段出现了几次"时靠它,比如排查重复键名。
折叠用在两个方向。一个是排除:确认某个分支和我要找的东西无关,就把它收起来,剩下的可视区域立刻变小。另一个是压缩上下文:我关心 data.page,那就把 data.list 两个元素全部收起,屏幕上只剩几行。
复制路径是给"输出"用的。定位到字段之后,我要把它变成代码里的取值表达式、变成给后端的说明、变成测试用例里的断言目标,路径字符串就是中间那层通用语言。
至于纯文本美化或压缩回去,那是另一件事。要把 JSON 贴回代码或减小体积时我用 JSON格式化;树形视图负责读,格式化负责写,我不再用格式化去代替定位。
还有一类需求搜索框解决不了:我要找的是"所有以 _url 结尾的键"这种模式匹配。关键字搜索在这里帮不上忙,我会把内容交给 正则表达式测试,先在纯文本上把候选行捞出来,再回树里确认层级。
Q:为什么我搜 "name" 命中的位置跟我要找的字段不一样?
因为 "name" 在嵌套结构里出现很多次,命中顺序只是文本位置顺序。先看有几处命中,再用上一个、下一个逐个跳,配合折叠排除无关分支。
Q:树形视图和格式化,只需要一个吗?
看数据用视图,改数据用格式化。视图给的是结构与路径,格式化给的是可粘贴的文本;两个方向相反,用一个替另一个会别扭。
Q:很长的数组能不能只看前几条?
我的做法是折叠掉不需要的那些元素,只展开关心的下标。逐个展开一千条元素没有意义,问题通常在个别下标上。
Q:接口返回的 JSON 里有中文和转义符,会看不准吗?
值里的转义字符(比如 \n 和 \")在树里显示的是字符本身,读的时候把它按原字符理解就行;真要处理转义是写代码那一步的事。
Q:数据涉敏,不敢往线上工具里贴。
我的判断标准是看它有没有把内容发出去。这类工具如果只在浏览器本地处理,数据不出机器,敏感返回体我也敢直接粘;换成需要上传的方案我就换成本地编辑器加插件。
那次找了半小时的 "shop_name",最后的答案是它在 data.list[1].items[0] 下面,而我要的那条记录在第 0 个元素里——两个都有同名字段,我一开始撞上的就是错的那个。从那以后我先数命中处数,再决定展开哪一支,顺序和以前完全反了,这大概是这类问题最实际的解法。