ArkTS JSON.parse 崩溃排查指南:从“天书日志”到精准定位
本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:
凌晨,你正准备合上电脑,测试同学在群里甩来一张崩溃截图:
Reason: SyntaxError
Error name: SyntaxError
Error message: Unexpected end Text in JSON at position 15, e":"v*l*e","a*e"
你翻开源码,找到调用 JSON.parse 的那一行。传进去的字符串看起来没问题啊?变量名是 str,内容是 {"name":"value","age"——
等等,"age" 后面没了?
对,就是这么低级的错误。但问题在于:线上崩溃日志里,你根本看不到原始字符串长什么样。JSON 可能包含用户昵称、手机号、地址等敏感信息,日志当然不能明文输出。
于是你只能看到一个被“打码”的片段,和一行不知道从哪来的调用栈。这篇文章,就是教你如何从这堆“天书”里,把真凶揪出来。
一、先搞清楚:这个错到底在说什么
Unexpected xxx in JSON 本质上只有一个原因:你传给 JSON.parse() 的字符串,不是合法的 JSON。
仅此而已。但“不合法”的方式五花八门,崩溃日志会告诉你具体是哪一种:
| 错误信息片段 | 根本原因 | 正确写法 |
| Unexpected end Text in JSON | 对象或数组没闭合 | 补全 } 或 ] |
| Unexpected Number in JSON | 数字有前导零(如 0123) | 去掉前导零 |
| Unexpected Text in JSON | 布尔值拼错(如 ture) | 改成 true |
| Unexpected end Text in JSON | 字符串缺引号 | 补全双引号 |
看起来挺直观对吧?但真实场景里,问题往往不在这几个字面量上,而在于数据从哪来。
二、API 24 之前 vs 之后:为什么这个错误突然变得好查了
在 API 24 之前,崩溃日志只告诉你“位置 15 处有个 unexpected end”,你完全不知道第 15 个字符是什么。
API 24 开始,系统做了一件很关键的事:在错误日志里输出匿名化的 JSON 字符串片段,以错误位置为中心,前后各截取 15 个字符。
更关键的是匿名化规则——结构字符({ } [ ] " : , \r \t \n 空格)原样保留,非结构字符按“保留一位、脱敏一位”交替处理。也就是说:
e":"v*l*e","a*e" → 还原后约为 "value","age
因为 v*l*e 是 value 被打码,a*e 是 age 被打码。结合 position 15 这个位置信息,你可以直接推断出原始字符串是:
{"name":"value","age
age 后面既没有冒号,也没有值,更没有 }。根因确认:手写 JSON 字符串时漏写了 :21}。
三、两个真实案例,看懂“匿名片段 + 位置”怎么用
案例一:JSON 字符串提前结束
崩溃日志:
Error message: Unexpected end Text in JSON at position 15, e":"v*l*e","a*e"
Stacktrace:
at anonymous entry (entry/src/main/ets/pages/UnexpectedXXXInJSONCase.ets:37:18)
定位到源码第 37 行:
let str = "{\"name\":\"value\",\"age\""; // 👈 缺了 :21}
let obj = JSON.parse(str);
修复很简单:补全 :21} 即可。
案例二:数字前导零
崩溃日志:
Error message: Unexpected Number in JSON at position 10, {"v*l*e":0*2*}
还原匿名片段:{"value":0123}。位置 10 正好指向 0123 里的第一个 0——JSON 规范不允许数字有前导零(除非数字本身就是 0,或者像 0.123 这样后面紧跟小数点)。
修复:
let str = "{\"value\":123}"; // 去掉前导零
四、真正的坑,在数据来源
案例里的 {"name":"value","age" 是手写字符串,一眼就能看出来。但线上的崩溃往往来自更隐蔽的地方。
HarmonyOS 开发者社区里有一个高频问题:请求服务端数据时,如果返回的 value 值包含换行符,JSON.parse 就会报 Unexpected end Text in JSON。
原因很简单:换行符 \n 在 JSON 字符串值里是非法字符,必须转义成 \\n。但后端拼接响应体时没做转义,前端拿到就直接 JSON.parse,崩溃就来了。
社区里的解决方式是先对换行符做转义再解析。但这只是治标——真正的治本方案是让数据源产出合法 JSON。
另一个高频场景是认证服务。有开发者反馈:首次启动 auth 模块正常,关闭后台重新启动后调用 auth.getCurrentUser() 就报 Unexpected end Text in JSON,连 AGC 下载的 agconnect-services.json 都出问题。排查到最后发现是 JSON 内容在读取后发生了变化,需要对比前后内容才能定位。
五、三条防线,把问题挡在崩溃之前
防线一:用 JSON.stringify 生成字符串
手写 JSON 字符串是崩溃的第一大来源。键没加双引号、值用了单引号、漏了逗号、括号不匹配——每一个都是崩。
// ❌ 手写,迟早出事
let str = "{name: 'value'}";
// ✅ 用对象 + stringify
let obj = { name: "value", value: 123 };
let str = JSON.stringify(obj);
防线二:所有 JSON.parse 必须包在 try-catch 里
这不是“最佳实践”,这是底线。JSON.parse 抛的是运行时异常,不 catch 就直接崩。
try {
let obj = JSON.parse(inputStr);
} catch (e) {
console.error(`JSON解析失败: ${e.message}, 原始字符串: ${inputStr}`);
// 降级处理或上报
}
对于页面级逻辑,这条规则尤其重要。在 onPageShow 里调接口然后直接 JSON.parse,一旦失败又没 catch,用户看到的就是白屏。
防线三:对外部数据保持怀疑
网络返回的、文件读取的、用户输入的——都不是你生成的,都不能信任。
• 网络请求显式指定 HttpDataType.STRING,让解析由应用控制
• 解析前先用 JSON 验证工具检查结构
• 字符串可能被截断时,检查完整性标志
• 后端返回非标准 JSON(如 NaN、undefined)时,先处理再解析
总结
Unexpected xxx in JSON 看起来是一个“JSON 写错了”的简单问题,但线上崩溃的复杂性在于:你看到的是经过匿名化处理的片段,而不是原始字符串。
读懂匿名片段 + 位置信息 + 调用栈,是定位这类问题的核心能力。API 24 增强的错误日志已经大幅降低了门槛——匿名片段还原后,大多数情况下一眼就能看出缺了什么。
预防的核心只有一句话:避免手写 JSON,多用 JSON.stringify();解析前加 try-catch;对外部数据保持怀疑。
下次再看到 e":"v*l*e","a*e" 这样的片段,别慌。把结构字符挑出来,把脱敏字符补回去,位置数字对一下,真凶就在那里。
🔗 官网开发者学堂视频:华为开发者学堂

🔗 社区DFX专题文章: 华为开发者问答 | 华为开发者联盟


【扫码加入 HarmonyOS DFX 技术交流群】
更多推荐

所有评论(0)