在线JS游戏扩展中,如何Eval含控制字符的JSON字符串?
问题描述
我正在给一款在线JavaScript游戏写工具箱扩展,需要生成命令字符串传给注入脚本,由脚本用eval执行。现在遇到个问题:当要传递的对象包含控制字符(比如换行符\n)时,eval解析会失败。
可行场景(无控制字符)
const ObjectToPass = {a:"test"} const ObjectStringified = JSON.stringify(ObjectToPass) // '{"a":"test"}' const StringToPass = `Destination = JSON.parse('${ObjectStringified}')` // 传递到主页面上下文后执行eval eval(StringToPass) // Destination 成功赋值为 {a:"test"}
失败场景(含控制字符)
const ObjectToPass = {a:"test\n"} const ObjectStringified = JSON.stringify(ObjectToPass) // '{"a":"test\\n"}' const StringToPass = `Destination = JSON.parse('${ObjectStringified}')` // 主页面执行eval后报错 eval(StringToPass) // 报错:Uncaught SyntaxError: Bad control character in string literal in JSON at position 10
我试过各种转义组合和双重stringify/parse,都没解决,比如这些尝试都失败:
eval(`JSON.parse('{"a":"\\n"}')`) // 报错:Invalid or unexpected token eval(`JSON.parse('{"a":"\\n"}')`) // 报错:Bad control character... eval(`JSON.parse('{"a":"\\\n"}')`) // 结果不对:{a: ''} eval(`JSON.parse(\`{"a":"\\n"}\`)`) // 报错:Bad control character...
问题根源
问题出在字符串嵌套解析的转义层级:
JSON.stringify把\n转成了\\n,得到的JSON字符串是'{"a":"test\\n"}'- 当把这个字符串塞进单引号模板
'${ObjectStringified}'后,最终传给eval的代码是Destination = JSON.parse('{"a":"test\\n"}') eval会先解析这个字符串字面量,把\\n变成实际的换行符\n,此时传给JSON.parse的内容变成了{"a":"test\n"}- 而JSON规范不允许字符串里出现未转义的控制字符(比如实际的换行符),所以直接报错。
解决方案
方案1:直接传递JSON作为对象字面量(推荐)
不需要用JSON.parse,直接把JSON.stringify后的结果当作对象字面量赋值,跳过解析步骤:
const ObjectToPass = {a:"test\n"} const ObjectStringified = JSON.stringify(ObjectToPass) const StringToPass = `Destination = ${ObjectStringified}` // 主页面执行eval eval(StringToPass) // Destination 成功赋值为 {a:"test\n"}
这样eval会直接把JSON字符串当作JS对象解析,完全避开了转义冲突问题。
方案2:二次转义JSON字符串(如果必须用JSON.parse)
如果因为某些原因一定要用JSON.parse,需要把JSON字符串里的反斜杠再转义一次,确保eval解析后传给JSON.parse的是正确的转义序列:
const ObjectToPass = {a:"test\n"} let ObjectStringified = JSON.stringify(ObjectToPass) // 把所有反斜杠替换成双重反斜杠 ObjectStringified = ObjectStringified.replace(/\\/g, '\\\\') const StringToPass = `Destination = JSON.parse('${ObjectStringified}')` // 主页面执行eval eval(StringToPass) // Destination 成功赋值为 {a:"test\n"}
此时传给eval的代码是Destination = JSON.parse('{"a":"test\\\\n"}'),eval解析后变成JSON.parse('{"a":"test\\n"}'),JSON.parse就能正确识别\\n为换行符。
内容的提问来源于stack exchange,提问作者Ufodynasty
相关产品推荐
相关产品推荐

