处理来自 API 的 JSON 中的语法错误

Posted

技术标签:

【中文标题】处理来自 API 的 JSON 中的语法错误【英文标题】:Handle syntax error in JSON coming from API 【发布时间】:2017-07-05 09:49:25 【问题描述】:

想象一下 JSON (, instead of :) 中的以下语法错误:

[
    
        "name": "anna",
        "email": "anna@gmail.com",
        "town", "london"
    ,
...
]

我想知道是否可以处理此错误而不是获取异常、获取错误对象、更正错误并继续使用正确的版本。

这是我的 Angular 服务的一部分;我正在尝试获取文本而不是 JSON 数据,但它不起作用...

 angular.module('mine', [])
    .config(function($sceProvider) 
        // Completely disable SCE.  
        $sceProvider.enabled(false);
    )
    .config(['$sceDelegateProvider', function($sceDelegateProvider) 
        $sceDelegateProvider.resourceUrlWhitelist([
        'self',
        'http://www.mocky.io/v2/5807df4a10000004122b74e2'
        ]);
    ])
  .config(function ($httpProvider) 
        $httpProvider.interceptors.push(function($q) 
            return 
                'request': function(config) 
                    config.headers.Accept = 'text/plain';
                    return config;
                ,
                'response': function(response) 
                    try 
                        // try to parse it
                        response.data = JSON.parse(response.data);  
                     catch (ex) 
                        // try to fix it
                        console.log("error " + ex);
                        console.log(response.data);
                        response.data = fixed_data : "data";
                    
                    // return the corect data.
                    // note that the original response.data WILL BE CHANGED and this is expected.
                    return response;
                
            ;
        );
  )



       angular.module('mine').factory('MyFactory', ['$http','$q',  function MyFactory($http,$q) 
        return 
            getData: function()     
                var deferred = $q.defer(),
                config = 
                        params:  
                    ,

                url="http://www.mocky.io/v2/5807df4a10000004122b74e2";          

                $http.jsonp(url,config)
                .then(              
                    function (response) 
                        deferred.resolve(response.data);
                    ,  
                    function (error) 
                        console.log(error);
                        return $q.reject('Error retrieving data');
                    
                );

                return deferred.promise;
            
        ;
 ]);

有没有办法将上述承诺引导到成功回调中,检索错误的 JSON 并纠正它?根据上面的示例,我该如何编码?

或者更简单的方法,如何从 $http.jsonp 检索文本而不是 JSON 数据,以免被驱动到失败回调?

【问题讨论】:

如果它以字符串形式返回,您可能会做一个正则表达式并将其查找/更改为正确的 JSON 语法,然后像往常一样使用 JSON.parse 它。 是的,当然可以。 这里的问题是因为语法错误,不是JSON,也不是有效的JSON。另外,从良好实践的角度来看,这确实应该在服务器端进行处理。 是的,有可能,transforming the response。但请注意,JSON 标准之所以严格是有原因的,正确的处理方法是使用该标准来传输信息。 我希望能用一些代码提供更具分析性的答案 【参考方案1】:

简短回答:不,没有。

长答案:如果您的 JSON 序列化在后端不起作用,您基本上必须自己解析一个字符串并构造一个新对象。没有图书馆可以为您做到这一点。想想不同的后端服务。

【讨论】:

【参考方案2】:

我总体上同意@Florian 的回答 - 没有简单的方法。 我认为你应该:

想办法找到问题所在; 替换逗号; 重新解析为 JSON。

找到问题所在的想法:在每一秒(偶数)值之后需要一个逗号。每一秒后(奇数 - 1., 3., 5) - 一个冒号。在每个新的 上,您必须开始一个新的计数。这可能很麻烦,但可行。

【讨论】:

如何将承诺重定向到成功回调中以执行上述所有操作?它进入失败回调... 不要将其视为 JSON。接受它作为一个字符串。收到后,尝试解析它以处理可能的错误(try/catch)。只有在 'catch' 中你才会出错。 既然我必须使用$http.jsonp,我怎样才能返回一个字符串而不是JSON?【参考方案3】:

你可以使用 douglascrockford 的JSON-js。如果它不是一个有效的 json,它会抛出一个错误,以便你可以使用 try/catch 捕获并返回一个新的 Promise 或简单的 true/false。如果您不使用该库,它将回退到内置解析器。

$http(
          method: "GET",
          url: '../data/data-feed.json'
      )
      .then(
          function (response) 
              console.log(response);
              try 
                 JSON.parse(json);
                 console.log("valid");
               catch (e) 
                 console.log("invalid");
                 // correct the invalid json here
              
          ,  
          function (error) 
              console.log('error');
          
      );

默认 JSON 解析器行为

function parseJSON (jsonString)
    try 
        var jString = JSON.parse(jsonString);
        if (jString && typeof jString === "object") 
            return jString;
        
    
    catch (e)  

    return false;
;
var inValidJson = '["name": "anna","email": "anna@gmail.com","town", "london"]';
var validJson = '["name": "anna","email": "anna@gmail.com","town": "london"]';
console.log("if invalid returns: ", parseJSON(inValidJson));
console.log("if valid get original object: ",parseJSON(validJson));

【讨论】:

【参考方案4】:

TL;DR

进一步了解 OP 问题后编辑:

在您想要编辑响应内容的一般情况下,您可以使用“拦截器”来执行此操作,但响应开始时应该是合法的。也就是说,如果您想将数字字符串更改为其他正确 JSON 中的整数 - 这是可能的。

在 JSON 格式错误的情况下,OP 会出现问题 - 这是不可能的!

长篇大论

首先

进入经典XY problem!

您真的应该问自己为什么 JSON 会损坏,而不是尝试在客户端代码中修复它。 想想看 - 如果你现在修复它只会遇到更多问题,然后有人会修复 API - 然后 将有损坏的代码。

如果 JSON 应该是:

[
    
        "name": "anna",
        "email": "anna@gmail.com",
        "addresses": ["town": "london", ..., ...]
    ,
...
]

或者(上帝保佑):

[
    
        "name": "anna",
        "email": ["anna@gmail.com","town", "london"]
    ,
...
]

你看 - 我的意思是 - API 坏了,它可以是任何东西。您应该修复 API。如果这个 API 不是你的来修复 -> 使用其他 API 或联系所有者来修复它。

JSONP

JSONP 是一种让 API 直接调用您的代码的方法。 您必须信任此 API。如果 API 会给我格式错误的 JSON,我会远离!

简而言之,JSONP 在 Angular(或实际上在任何地方)的工作方式是将<script> 标签注入到 DOM 中,src 指向 JSONp 请求的 URL。

服务器将填充带有函数名称的 JSON 数据(最常见的是 callback,但它可以是任何全局可访问的函数(Angular 使用 angular.callbacks._xyz)并将其发送。

浏览器然后调用从src下载的脚本

现在,问题是 浏览器 调用脚本。它不在 Angular 手中。而 that 正是 OP 面临的问题 - 脚本必须首先被评估为正确的 javascript,并且 浏览器 正在这样做,而不是 Angular。这是必须的。你不能进入它的中间。如果这样做,可能会带来安全风险。这就是为什么,例如,无论您要求什么,JSONP 请求的响应都会总是(按照惯例...)返回 MIME 类型为application/javascript

交战 - 这里是龙!

我劝你不要走这条路!

如果您坚持从 JSONP 调用中获取带有错误的 JSON(我所说的错误是指 JSON 可以被解析为对象但是有些东西您想更改该对象)您可以尝试添加“Interceptors”

.config(function ($httpProvider) 
    $httpProvider.interceptors.push(function($q) 
        return 
            'request': function(config) 
                // here you can edit the request.
                return config;
            ,
            'response': function(response) 
                // response.data will hold your bad data
                // you could edit it
                response.data = fix(response.data);
                // return the correct data.
                return response;
            
        ;
    );
)

注意你也可以Overriding the Default Transformations

另外,请务必:

   // Whitelist the JSONP endpoint that we are using to show that we trust it
  .config(['$sceDelegateProvider', function($sceDelegateProvider) 
    $sceDelegateProvider.resourceUrlWhitelist([
      'self',
      'https://your.api.url/**'
    ]);
  ])

如果一切顺利,您将可以致电:

//uncomment jsonpCallbackParam: 'callback' if your jsonp callback
//parameter at the backend uses some other name but the default 'callback'
$http.jsonp(https://your.api.url/*,jsonpCallbackParam: 'callback'*/)
.then(function(response) 
    $scope.status = response.status;
    $scope.data = response.data;
  , function(response) 
    $scope.data = response.data || 'Request failed';
    $scope.status = response.status;
);

【讨论】:

这不能回答我的问题!! 很抱歉你这么认为。 如果您可以更改以上内容以使用 $http.jsonp,那么赏金积分就是您的了。 @ILIAS 是对的!这实际上是你的问题。修复用户输入是一种糟糕的代码实践。 好的,我知道;但是,我想在特殊情况下那样工作。有人知道怎么做吗?【参考方案5】:

这是可能的,但很麻烦。出于It-Z 的原因,通常最佳实践是修复 API 提供的 JSON 或寻找新的 API 来使用。假设您有不这样做的理由,以下是逻辑流程:

从 JSON.parse 中捕获错误并将其与未解析的响应字符串一起提供给新函数 在那个新功能中 如果您知道您的错误只会出现这种情况,请创建逻辑来查找并修复它;正则表达式将成为您的朋友 如果您试图捕捉多种类型的语法问题,您将需要更复杂的正则表达式和更复杂的逻辑 将更正后的字符串传回原来的 JSON.parse 函数

【讨论】:

以上是关于处理来自 API 的 JSON 中的语法错误的主要内容,如果未能解决你的问题,请参考以下文章

详解JavaScript中的异常处理方法

HBuilder X 提示Setting.json格式语法错误

确定 VBA 中当前错误处理方法的语法

使用 axios 处理来自异步等待语法的错误

安全地处理节点中的错误 JSON.parse()

PHP的错误处理