侧边栏壁纸
博主头像
一笑痕

人生若只如初见,
是可喜亦或者是可悲?

  • 累计撰写 206 篇文章
  • 累计收到 7 条评论

JSON.parse 成功,工具参数仍可能不是对象

2026-10-17 / 0 评论 / 7 阅读

JSON.parse 成功,工具参数仍可能不是对象

JSON.parse 没抛异常,不等于工具拿到了能用的参数。若工具约定接收 { "city": "杭州", "unit": "c" },传入 []、null、"杭州" 或 42 也都是合法 JSON。解析器只负责语法,不替某个工具决定输入形状。

本机用 Node.js 跑了几组固定字符串,结果很直观:只有正确形状并满足字段要求的对象被接受。验证脚本放在 tools/verify-tool-args-object-shape-20261017.mjs,没有调用模型或网络。各类失败都来自写死的输入,观察范围只到这个小校验器,不涉及任何工具服务端的行为。

先问解析结果是什么类型

  1. 数组也是对象的一种,但不是工具参数对象。JavaScript 里 typeof [] 得到 "object",所以只写 typeof value === 'object' 会让数组通过。null 也有同样的 typeof 结果,需要单独排除。
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
  return 'expected a JSON object';
}

脚本里这条规则拒绝了顶层数组和 null,也拒绝了字符串、数字。JSON.parse 对这些输入都能成功,错误出现在后续的形状校验,而不是语法解析。若不先挡住类型,后面的 value.city.trim() 可能对 undefined 或数字调用字符串方法,问题会变成运行时异常,而不是一条清楚的参数错误。越靠近输入边界解释,越容易保留原始输入和对应调用记录。

键存在和键值有效是两回事

  1. 先检查必需键是否自有,再校验值的类型和范围。对 city 与 unit 而言,缺少 unit 和 unit: null 都不满足约定,但原因不同:前者没有键,后者有键但值不合格。解析出来的对象用 Object.hasOwn 检查键,比用真值判断更准确,空字符串和 null 不会被误当成「键不存在」。
for (const key of ['city', 'unit']) {
  if (!Object.hasOwn(value, key)) return `missing required key: ${key}`;
}
if (typeof value.city !== 'string' || value.city.trim() === '') {
  return 'city must be a non-empty string';
}
if (value.unit !== 'c' && value.unit !== 'f') {
  return 'unit must be "c" or "f"';
}

这也解释了为什么「能读到某个属性」不是完整检查。普通对象可能从原型链继承属性;JSON.parse 生成的对象也有 Object.prototype,只是 JSON 文本里的字段本身是自有属性。hasOwn 把规则写得明确,不依赖对象来源。

一个小校验器只负责它声明的约定

  1. 这段逻辑没有实现完整 JSON Schema,也不声称检查了所有业务规则。它要求顶层为非 null、非数组对象,要求 city 是非空字符串,并把 unit 限定为 c 或 f。字段名与约束都来自这个示例工具的本地约定。

脚本没有拒绝额外字段。若工具需要拒绝未知键,应再枚举允许字段并检查;若 city 还要匹配某个地区清单,也应加独立规则。如果上游把参数转成对象后立刻调用工具,校验的位置应在工具分发之前。这样坏输入不会触发实际动作,错误日志也能保留解析后的键和值。具体项目还要决定是否记录敏感字段,示例没有处理日志脱敏或权限控制。

校验通过只说明输入符合这里写下的约定。它不证明地点存在,也不代表调用者有权查询该地点;这些判断不属于 JSON 语法或对象形状检查。

  1. 语法损坏时,JSON.parse 抛出异常;合法 JSON 但形状或字段不合约时,解析成功、校验器拒绝。把两类错误分开记录,日志才说明失败发生在哪一层。重试策略也能据此决定:修复截断或转义问题,与缺少必需键不是同一类动作。

实际输出如下。数值和错误文字来自脚本运行结果,不是模型响应。

node v26.8.1
固定样例;只调用 JSON.parse 和本地校验器,不调用模型或网络。
ACCEPT valid object: valid arguments
REJECT top-level array: expected a JSON object
REJECT top-level null: expected a JSON object
REJECT top-level string: expected a JSON object
REJECT top-level number: expected a JSON object
REJECT missing required key: missing required key: unit
REJECT wrong field type: city must be a non-empty string
PARSE_ERROR invalid JSON: SyntaxError

把问题概括成「解析成功就检查字段」会漏掉最前面的一道门:先确认顶层类型。只查属性会让数组、null 等意外输入走进后续逻辑,随后报出更难定位的错误;先检查形状,再查必需键和值,失败位置更清楚。我不建议把 JSON.parse 的成功当作调用许可,它只说明文本可解析。

    🤞 分享