/ 开发笔记

Javascript解析JSON字符串报错:parse failed: SyntaxError: Unexpected token n in JSON

问题背景

有个JavaScript对象obj,其中一个属性值为另一个对象child的JSON stringify后得到的JSON字符串。

大概是这样子

	var child = {
		number: 123,
		string: "abc"
	};
	var childValue = JSON.stringify(child);
	var obj = {
		data: [
			{
				key: "mykey",
				value: childValue
			}
		]
	}

obj对象的数据被JSON化后存储在服务器上,读取时,服务器也用JSON格式发送obj对象数据。

但是,奇怪的是,在对服务端获取的obj JSON数据进行解析时,报错了

parse failed:  SyntaxError: Unexpected token n in JSON at position 54

这是为什么呢?

解决方法

为了解决这个问题,写了一个简单的js测试用例,如下。

try{
	var child = {
		number: 123,
		string: "abc"
	};
	var childValue = JSON.stringify(child);
	var obj = {
		data: [
			{
				key: "mykey",
				value: childValue
			}
		]
	}

	var objJson = JSON.stringify(obj);

	console.info("child json ===> ", childValue);
	console.info("=============================\n");

	console.info("obj json ===> ", objJson);
	console.info("=============================\n");
	
	var b = JSON.parse(objJson);
	console.info("obj parse from json => ", b);
	console.info("=============================\n");


	var objJson3 = `
	{
		"data":[
			{
				"key":"mykey",
				"value":"{\\\"number\\\":123,\\\"string\\\":\\\"abc\\\"}"
			}]
		}
	`;

	var objJson2 = `
	{
		"data":[
			{
				"key":"mykey",
				"value":"{\"number\":123,\"string\":\"abc\"}"
			}]
		}
	`;

	var c = JSON.parse(objJson3);
	console.info("obj3 parse from json => ", c);
	console.info("=============================\n");

	c = JSON.parse(objJson2);
	console.info("obj2 parse from json => ", c);
	console.info("=============================\n");

	// var v = b.data[0].value;
	// console.info("value: ", v);
	// var vo = JSON.parse(v);
	// console.info("value to object: ", vo);
}catch(e){
	console.info("parse failed: ",e);
}

运行结果

node test.js
child json ===>  {"number":123,"string":"abc"}
=============================

obj json ===>  {"data":[{"key":"mykey","value":"{\"number\":123,\"string\":\"abc\"}"}]}
=============================

obj parse from json =>  { data: [ { key: 'mykey', value: '{"number":123,"string":"abc"}' } ] }
=============================

obj3 parse from json =>  { data: [ { key: 'mykey', value: '{"number":123,"string":"abc"}' } ] }
=============================

parse failed:  SyntaxError: Unexpected token n in JSON at position 54
    at JSON.parse (<anonymous>)
    at Object.<anonymous> (/Users/zhangzhibin/Documents/mygit/temp/test.js:54:11)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47

发现,从服务端读取的obj数据是objJson2,该数据中,child的json串中增加了一些转义字符(由斜杆\开头)。
这是正常的,JSON字符串需要对特殊字符进行转义才能保存。

而报错的位置,正是第一个转移字符:
json-parse-failed-syntax-error-unexpected-token-01

仔细分析一下,JavaScript的JSON.parse在解析时,可能先对字符串中的转义字符进行转义,其中

\" => "

所以,objJson2等同于

	var objJson2 = `
	{
		"data":[
			{
				"key":"mykey",
				"value":"{"number":123,"string":"abc"}"
			}]
		}
	`;

而这,显然不是一个合法的JSON串了。

同理,对于objJson3,对转义字符进行一次处理:

\\ => \
\" => "

得到:

	var objJson3 = `
	{
		"data":[
			{
				"key":"mykey",
				"value":"{\"number\":123,\"string\":\"abc\"}"
			}]
		}
	`;

这是一个合法的嵌套了JSON串的JSON串。

如何处理这种情况

有几个方案:

    1. 对特殊字符串进行编码
      例如,在保存的时候,将内嵌的json串进行base64编码,在读取后,进行base64解析。
    1. 在读取时对转义字符进行二次转义
      例如,将服务端读取的字符串中
\ 替换成 \\

注意,如果在java中使用这种方案,需要

strBsf.replaceAll("\\\\", "\\\\\\\\")

参考: https://www.cnblogs.com/yanduanduan/p/7157877.html