【问题标题】:JavaScript: Unable to parse json with error unexpected tokenJavaScript:无法解析带有错误意外令牌的 json
【发布时间】:2025-11-29 12:45:01
【问题描述】:

我以前设法用 java 代码解析一个 json url,但现在需要将它迁移到 javascript。当我使用 JavaScript 解析时,语法错误:我发生了意外的令牌

SyntaxError: Unexpected token i in JSON at position 2
at JSON.parse (<anonymous>)
at success (homeCtrl.js:1060)
at processQueue (ionic.bundle.js:29127)
at ionic.bundle.js:29143
at Scope.$eval (ionic.bundle.js:30395)
at Scope.$digest (ionic.bundle.js:30211)
at Scope.$apply (ionic.bundle.js:30503)
at done (ionic.bundle.js:24824)
at completeRequest (ionic.bundle.js:25022)
at XMLHttpRequest.requestLoaded (ionic.bundle.js:24963)
(anonymous) @ ionic.bundle.js:26794
(anonymous) @ ionic.bundle.js:23507
processQueue @ ionic.bundle.js:29135
(anonymous) @ ionic.bundle.js:29143
$eval @ ionic.bundle.js:30395
$digest @ ionic.bundle.js:30211
$apply @ ionic.bundle.js:30503
done @ ionic.bundle.js:24824
completeRequest @ ionic.bundle.js:25022
requestLoaded @ ionic.bundle.js:24963 

我的javascript如下:

//scrap singapore
function topVolumeGainerLosersSingapore(type) {
$ionicLoading.show();

var url = "http://www.sgx.com/JsonRead/JsonData?qryId=RStock&timeout=30";

$http({
method: 'GET',
url: url,
transformResponse: undefined,
headers: {
"Content-Type":"text/plain",
"Accept":"text/plain"
}
}).then(function success(response) {
// this function will be called when the request is success
var text = response.data;
//console.log(text);
var replaceData = text.substring(text.indexOf("&&")+2);
//console.log(replaceData);
var newData = JSON.parse(replaceData);
console.log(newData);

}, function error(response) {
// this function will be called when the request returned error status
$ionicLoading.hide();
console.log(response);
});
}

对于同一个url,java代码可以正确解析,没有错误

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new AsyncTas().execute();
    }

    private class AsyncTas extends AsyncTask<Void,Void,Void>{

        @Override
        protected Void doInBackground(Void... voids) {
            HttpURLConnection urlConnection = null;
            String urlString = "http://www.sgx.com/JsonRead/JsonData?qryId=RStock&timeout=30";
            try {
                urlConnection = (HttpURLConnection) new URL(urlString).openConnection();
                //String result = readIt(new BufferedInputStream(urlConnection.getInputStream()));
                BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(urlConnection.getInputStream()));

                // Grab the results
                StringBuilder log = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    log.append(line + "\n");
                }
                String result = log.toString();

                result = result.substring(result.indexOf("&&") + 2);
                JSONObject jo = new JSONObject(result);

                Log.e(TAG, "doInBackground: "+result);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
                Toast.makeText(getApplicationContext(),"Unable to parse json "+e.getMessage(),Toast.LENGTH_LONG).show();
            }
            return null;
        }
    }
}

想要的输出如下:

{identifier:'ID', label:'As at 08-03-2017 2:48 PM',items:[{ID:0,N:'3Cnergy',SIP:'',NC:'502',R:'',I:'',M:'t',LT:0.000,C:0.000,VL:0.000,BV:100.000,B:'0.042',S:'0.047',SV:70.000,O:0.000,H:0.000,L:0.000,V:0.000,SC:'2',PV:0.040,PTD:'20170307',BL:'100',EX:'',EJ:'',CLO:'',P:0.0,P_:'X',V_:''},{ID:1,N:'800 Super',SIP:'',NC:'5TG',R:'',I:'',M:'t',LT:1.160,C:-0.020,VL:51.400,BV:10.500,B:'1.160',S:'1.170',SV:10.000,O:1.180,H:1.180,L:1.160,V:60324.500,SC:'A',PV:1.180,PTD:'20170307',BL:'100',EX:'',EJ:'',CLO:'',P:-1.694915234375,P_:'X',V_:''},{ID:2,N:'8Telecom',SIP:'',NC:'AZG',R:'',I:'',M:'',LT:0.000,C:0.000,VL:0.000,BV:5.000,B:'0.130',S:'0.140',SV:10.000,O:0.000,H:0.000,L:0.000,V:0.000,SC:'2',PV:0.135,PTD:'20170306',BL:'100',EX:'',EJ:'',CLO:'',P:0.0,P_:'X',V_:''},{ID:3,N:'A-Smart',SIP:'',NC:'BQC',R:'',I:'',M:'',LT:0.570,C:-0.020,VL:60.000,BV:31.000,B:'0.570',S:'0.580',SV:10.000,O:0.575,H:0.575,L:0.570,V:34350.000,SC:'2',PV:0.590,PTD:'20170307',BL:'100',EX:'',EJ:'',CLO:'',P:-3.38983046875,P_:'X',V_:''}, 

【问题讨论】:

    标签: javascript java json


    【解决方案1】:

    源数据似乎不包含有效的 JSON 数据。根据http://json.org/,键是字符串,因此必须用双引号括起来,这也适用于字符串值:

    { "identifier": "ID" }
    

    正如您的错误所述,解析器期望的是双引号,而不是 i 字符。

    我建议你先用一个小的 sn-p 测试你的代码,以验证它是否适用于有效的 JSON 数据。

    【讨论】:

    • 这就是 JSON.parse 和 eval() 的区别。第一个需要严格的 JSON,另一个需要 JavaScript。您的源数据以最后一种格式写入。见w3schools.com/js/js_json_syntax.asp
    • @BjörnM,您可以建议任何解决方法吗?谢谢
    • 我认为@holi-java 在他的回答中已经提供了这一点
    • 在我看来,修复输入,即严格 JSON,是最简单的解决方案。
    【解决方案2】:

    使用 eval 代替。您的 json 数据不是严格模式。严格模式 json 数据的键必须双引号。

    演示

    var json="{} && { identifier: 'ID' }";
    
    function test(json,parser){
      try{
      console.log("parsing by "+parser.name+" => "+JSON.stringify(parser("("+json+")")));
      }catch(e){
        console.log('Can not parsed by '+parser.name);
      }
    }
    test(json,JSON.parse);
    test(json,eval);

    JSON.parse 仅支持严格模式

    var formats={
     strict:'{"foo":"bar"}',
     'single-quotes':"{'foo':'bar'}",
     'no-quotes':"{foo:'bar'}"
    };
    
    function test(parser){
      return parser.name+" supports " +Object.keys(formats).reduce(function(supports,format){
        try{
           parser(formats[format]);
           supports.push(format);
        }catch(e){      
        }finally{return supports;}
      },[]);
    }
    function parseJSON(json){
     return eval("("+json+")");
    }
    console.log(test(parseJSON));
    console.log(test(JSON.parse));

    封装eval()解决安全问题。

    window.$ = window.jQuery = {};
    function foo() {
        return 'bar';
    }
    
    parse = (function () {
        //disable all global keys
        eval("var " + Object.keys(window).join(', '));
    
        return function (_) {
            return eval("(" + _ + ")");
        };
    })();
    
    
    var snippets = [
        "window",
        "location",
        "$",
        "jQuery",
        "location.href='http://www.example.com'",
        'local',
        "{foo:'bar'}",
        "foo()",
        "eval('window')",
        'function ref(){return window}()'
    ];
    snippets.forEach(function (snippet) {
        var local = 'local value';
        var expression = "parse(" + JSON.stringify(snippet) + ")";
        try {
            console.log(expression + " => " + JSON.stringify(parse(snippet)));
        } catch (e) {
            console.error(expression + " failed!");
        }
    });

    【讨论】:

    • 出于安全和效率的原因,不应将 Eval() 用于 JSON 解析。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…!
    • @BjörnM eval 存在安全问题,但您可以将其封装为不允许访问其他只有全局变量才能访问的访问。
    • 在我看来,简单地修复输入比复杂的遗留解决方案更可持续。据我了解,提问者正在创建 JSON,因此可以在婴儿掉入井中之前修复它,而不是事后将其取出。如果您的解决方案无法解决遗留解析问题。
    最近更新 更多