admin管理员组文章数量:1301600
Imagine the following syntax error in JSON (, instead of :
):
[
{
"name": "anna",
"email": "[email protected]",
"town", "london"
},
...
]
I am wondering if it is possible to handle this error instead of getting an exception, getting the erroneous object, correct the error and go on with the correct version.
Here is a part of my Angular service; I am trying to get text and not JSON data but it does not work...
angular.module('mine', [])
.config(function($sceProvider) {
// Completely disable SCE.
$sceProvider.enabled(false);
})
.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
''
]);
}])
.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.jsonp(url,config)
.then(
function (response) {
deferred.resolve(response.data);
},
function (error) {
console.log(error);
return $q.reject('Error retrieving data');
}
);
return deferred.promise;
}
};
}]);
Is there anyway of directing the above promise into the success callback, retrieving the erroneous JSON and correcting it? How may I code that according to the above example?
Or maybe something easier, how to retrieve text and not JSON data from $http.jsonp
as not to be driven to the failure callback?
Imagine the following syntax error in JSON (, instead of :
):
[
{
"name": "anna",
"email": "[email protected]",
"town", "london"
},
...
]
I am wondering if it is possible to handle this error instead of getting an exception, getting the erroneous object, correct the error and go on with the correct version.
Here is a part of my Angular service; I am trying to get text and not JSON data but it does not work...
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;
}
};
}]);
Is there anyway of directing the above promise into the success callback, retrieving the erroneous JSON and correcting it? How may I code that according to the above example?
Or maybe something easier, how to retrieve text and not JSON data from $http.jsonp
as not to be driven to the failure callback?
- 3 If it es back as a string, you could probably do a regex and find/change it into proper JSON syntax, then just JSON.parse it as usual. – A. L Commented Feb 16, 2017 at 10:36
- Yes, it's possible, of course. – dfsq Commented Feb 16, 2017 at 10:38
- 1 The problem here is that because of the syntax error, it's not JSON, or valid JSON. Plus from a good practices point of view this should really be taken care of on the server side. – Craicerjack Commented Feb 16, 2017 at 10:38
- 1 Yes, it is possible, by transforming the response. Note, however, that the JSON standard is strict for a reason, and the correct way to deal with this is to use the standard to transfer information. – lonesomeday Commented Feb 16, 2017 at 10:40
- I 'd appreciate a more analytical answer with some code – Unknown developer Commented Feb 16, 2017 at 10:49
5 Answers
Reset to default 7 +50TL;DR
Edits after further understanding the OP problem:
In the generic case where you want to edit content of a response you can do it with "Interceptors" yet the response should be legitimate to begin with. That is, if you wanted to change numeric strings to integers in an otherwise correct JSON - it would be possible.
In the situation the OP is heaving where the JSON is malformed - it is just not possible!
The long story
First
Getting into a classic XY problem!
You should really ask yourself why is the JSON broken and not attempt to fix it in the client code. Think of it - You will only get into more problems if you fix it now, and later someone will fix the API - then you will have the broken code.
What if the JSON should have been:
[
{
"name": "anna",
"email": "[email protected]",
"addresses": [{"town": "london", ...}, ...]
},
...
]
Or (god forbid):
[
{
"name": "anna",
"email": ["[email protected]","town", "london"]
},
...
]
You see - my point is - The API is broken, it can be anything. You should fix the API. And if this API is not yours to fix -> use some other API or contact the owner to fix it.
JSONP
JSONP is a way to let APIs to call directly into your code. You must trust this API. If an API would have giving me malformed JSONs - I would stay away!
In short, the way JSONP works in Angular (or everywhere actually) is by injecting a <script>
tag into the DOM with src
pointing to the URL of the JSONp request.
The server will pad the JSON data with a function name (most often callback
but it can be any globally accessible function (Angular is using angular.callbacks._xyz
) and will send it.
The browser then invokes the script that was downloaded from the src
.
Now, the thing is that it is the browser calling the script. It is not in the hands of Angular. And that is exactly the problem the OP is confronting - the script must be evaluated as a correct JavaScript to begin with and the browser is doing that, not Angular. It is a MUST. You cannot get in the middle of it. It could pose a security risk if you do. This is why, for instance, the response of a JSONP request will always (by convention...) be returned with MIME type of application/javascript
no matter what you ask for.
Warring - here be dragons!
I urge you not to go in this path!
If you are insisting in getting from a JSONP call a JSON with errors (and by errors I mean that the JSON can be parsed as object yet there are some thing you want to change in that object) you could try to add "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;
}
};
});
})
Note that you could also Overriding the Default Transformations
Also, make sure to also to:
// 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/**'
]);
}])
And if all went well you will be able to call:
//unment {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;
});
You can use douglascrockford's JSON-js.If it is not a valid json it will throw an error so that you can catch using try/catch and return a new Promise or simple true/false. If you don't use the library it will fallback to built in parser.
$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');
}
);
Default JSON parser behavior
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": "[email protected]","town", "london"}]';
var validJson = '[{"name": "anna","email": "[email protected]","town": "london"}]';
console.log("if invalid returns: ", parseJSON(inValidJson));
console.log("if valid get original object: ",parseJSON(validJson));
Short answer: no there isn't.
Long answer: If your JSON serialisation does not work in the backend, you have basically to parse a string an construct a new Object by yourself. There is no library which does that for you. And think of a different backend service.
I agree to @Florian's answer in general - there is no simple way of doing so.
I think that You should:
- try to find a clever way to find the problem place;
- replace the ma(s);
- parse to JSON anew.
Idea of finding problem place: After every second (even) value there needs to be a ma. After every second (odd one - 1., 3., 5) - a colon. On each New {
You have to start a new count. It probably is a pain in the ass, but doable.
It's possible, but cumbersome. For reasons It-Z went into, generally the best practice would be to fix the JSON being served by the API or to find a new API to work with. Assuming you have your reasons for not doing that, here is the logic flow:
- catch the error from JSON.parse and feed it to a new function, along with the unparsed response string
- in that new function
- if you know you're only going to have this one case for your error, create logic to find and fix it; regex will be your friend here
- if you're trying to catch multiple types of syntax problems, you'll need more plex regex and much more plex logic
- pass the corrected string back to the original JSON.parse function
本文标签: javascriptHandle syntax error in JSON coming from APIStack Overflow
版权声明:本文标题:javascript - Handle syntax error in JSON coming from API - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741677257a2391956.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论