I am trying to catch specific response errors using jQuery's $.ajax.
When there is an 500 or 404 error code, instead of running the status code functions, it runs the error function and I get an alert box instead of what is supposed to happen
Here is what my code looks like
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
error: function(xhr, status) {
alert('There was a problem loading that page. You may need to refresh.');
},
statusCode: {
404: function(response) {
ajaxLoader.fetchPage('/missing');
},
500: function(response) {
ajaxLoader.fetchPage('/error');
}
}
}).done(callback);
},
This is by design. error is executed when an error is returned by the server. Further, the functions defined in statusCode are also called as well. The same applies to complete and success handlers.
You could modify your error handler not to run when the error code is already defined in statusCode.
$.ajax({
url: '/echo',
type: 'get',
success: function() {
console.log('ajax.success');
},
error: function(xhr, status) {
// check if xhr.status is defined in $.ajax.statusCode
// if true, return false to stop this function
if (typeof this.statusCode[xhr.status] != 'undefined') {
return false;
}
// else continue
console.log('ajax.error');
},
statusCode: {
404: function(response) {
console.log('ajax.statusCode: 404');
},
500: function(response) {
console.log('ajax.statusCode: 500');
}
}
});
Demo
The issue is that you are using the error callback in addition to the statusCode object. The error callback is triggered when any type of error occurs, including HTTP errors like 404 or 500.
To fix this, you need to remove the error callback and only use the statusCode object.
Here is the corrected code:
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
statusCode: {
404: function(response) {
ajaxLoader.fetchPage('/missing');
},
500: function(response) {
ajaxLoader.fetchPage('/error');
}
}
}).done(callback);
},
This way, only the appropriate function will be called when a 404 or 500 status code is returned, and not the error callback.
$.ajax has success and error functions, so you can handle it with jqXHR defined for both.
On success:
success: function(data, status, jqXHR) {
switch(jqXHR.status){
case 200:
//status ok
break;
case 206:
//Partial Content
//awesome code for handle it
break;
}
}
On error:
error: function(jqXHR, status, errorThrown) {
switch(jqXHR.status){
case 400:
//Bad Request
//awesome code for handle it
break;
case 404:
//Not Found
//awesome code for handle it
break;
}
}
Here all status codes
It will execute both the error and appropriate StatusCode function.
The only issue with your code is that in your StatusCode functions, you have the argument of response (which I assume is the argument for the success function), when it should match the error function arguments, as follows:
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
error: function(xhr, status) {
alert('There was a problem loading that page. You may need to refresh.');
},
statusCode: {
404: function(xhr, status) {
ajaxLoader.fetchPage('/missing');
},
500: function(xhr, status) {
ajaxLoader.fetchPage('/error');
}
}
}).done(callback);
},
With this, if a 404 or 500 is received, both the error function and the 404/500 function will execute. If you instead desire to have only the 404/500 function execute, and the error function will only execute if the returned status is not 404 or 500, you can do this as follows:
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
error: function(jqXHR, status) {
switch (jqXHR.status) {
case 404:
ajaxLoader.fetchPage('/missing');
break;
case 500:
ajaxLoader.fetchPage('/error');
break;
default:
alert('There was a problem loading that page. You may need to refresh.');
}
}
}).done(callback);
},
Related
<script>
function editComment(id) {
var content = $('#Content').val();
var modelData = { 'Id': id, 'Content': content };
$.ajax({
type: 'POST',
dataType: 'json',
url: '#Url.Action("EditC", "Comment")',
data: JSON.stringify({ model: modelData }),
contentType: 'application/json',
success: function () {
alert("YES");
},
error: function () {
alert("Error");
}
});
}
</script>
Here the server is returning 200 OK, but for some reason the error function is getting called. Both type and contentType seem to be correct. Any idea how to fix this?
Edit:
After adding
error: function (xhr, textStatus, error) {
console.log(xhr.responseText);
console.log(xhr.statusText);
console.log(textStatus);
console.log(error);
}
this is what is being logged:
parsererror
parsererror
SyntaxError: Unexpected end of JSON input
at parse (<anonymous>)
at ajaxConvert (jquery-3.4.1.js:9013:19)
at done (jquery-3.4.1.js:9483:15)
at XMLHttpRequest.<anonymous> (jquery-3.4.1.js:9785:9)
Moving to an answer for future readers...
The server is indeed returning a successful response, but an empty successful response:
return new HttpStatusCodeResult(200);
However, the client-side code is expecting valid JSON:
dataType: 'json',
As a result, after the successful response is received, internally the jQuery code attempts to parse that response as JSON and that fails, resulting in triggering the error callback.
Since there's no response body (and in most cases even when there is, as long as the server returns the correct MIME type), you don't need or want to specify a dataType in the jQuery AJAX operation. Simply remove this part:
dataType: 'json',
I have a Self-Hosted-Service(using WCF) that will run on clients machines. That service is supposed to make request to another server, get the data as XML then it returns to me that data as JSONP. Now i want to check if the service is running or not .. How can i check that ?
In my JS code i use $.getJSON with callback, so i tried to use .fail like this:
$.getJSON("http://localhost:8080/url?callback=?", function () {
alert("success");
}).fail(function () {
alert('fail');
})
but fail function didn't called when the server is not running(on chrome the Type is pending and Status is Failed)
Then i tried to use $.AJAX like this:
$.ajax({
type: 'GET',
dataType: 'jsonp',
url: 'http://localhost:8080/url?callback=?',
success: function (data, textStatus) {
alert('request successful');
},
error: function (xhr, textStatus, errorThrown) {
alert('request failed');
}
});
I got the same result.
When you make the AJAX request to your localhost and /url? returns weather the other server is up or not, your script won't fail. Because http://localhost/url is online.
I'd make the /url script return JSON array with remoteHostOnline: true or false,
then use:
$.ajax({
type: 'GET',
dataType: 'jsonp',
url: 'http://localhost:8080/url?callback=?',
success: function (data, textStatus) {
if (data.remoteHostOnline == false) {
alert('remote host not online');
}
}
});
You might have to tweak this script I didn't test it but you will understand what's wrong.
In a jquery Ajax call I am currently handling statusCode of 200 and 304. But I also have "Error" defined" To catch any Errors that could come back.
If there is a validation message related we return the status code of 400 - Bad Request.
This then falls into the "Error" function before falling into the statusCode "400" function I had defined. Which means two actions happen.
Ideally I would like to not define "Error" and "Success" and only define "statusCode" But what I need is to have a "Else" so that I don't need to declare every statusCode that exists only the 2-3 I want to handle differently.
$.ajax({
type: 'POST',
contentType: "application/json",
url: "../API/Employees.svc/" + EmployeeId + "/Company/" + CompanyId,
data: jsonString,
statusCode: {
200: function () { //Employee_Company saved now updated
hideLoading();
ShowAlertMessage(SaveSuccessful, 2000);
$('#ManageEmployee').dialog('close');
},
304: function () { //Nothing to save to Employee_Company
hideLoading();
$('#ManageEmployee').dialog('close');
if (NothingToChange_Employee) {
ShowAlertMessage(NothingToUpdate, 2000);
} else {
ShowAlertMessage(SaveSuccessful, 2000);
}
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
AjaxError(XMLHttpRequest, textStatus, errorThrown);
}
});
Since the "complete" event is always fired you could simply get the status code from there and ignore the success and error functions
complete: function(e, xhr, settings){
if(e.status === 200){
}else if(e.status === 304){
}else{
}
}
This is what i'd use:
error: function (xhr, textStatus, errorThrown) {
switch (xhr.status) {
case 401:
// handle unauthorized
break;
default:
AjaxError(xhr, textStatus, errorThrown);
break;
}
}
jQuery AJAX response complete, success, error have been deprecated. More up-to-date version with .done, .fail, .always promise instead.
On success .always has signature of .done, on failure it's signature changes to that of .fail. Using the textStatus you can grab the correct variable and return the body contents.
var jqxhr = $.ajax( {
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
dataType: 'json',
} )
.done(function( data, textStatus, jqXHR ) {
alert( "success" );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
alert( "error" );
})
.always(function( data_jqXHR, textStatus, jqXHR_errorThrown ) {
if (textStatus === 'success') {
var jqXHR = jqXHR_errorThrown;
} else {
var jqXHR = data_jqXHR;
}
var data = jqXHR.responseJSON;
switch (jqXHR.status) {
case 200:
case 201:
case 401:
default:
console.log(data);
break;
}
});
jqxhr.always(function() {
alert( "second complete" );
});
To keep the approach similar to your initial logic, I would continue passing a statusCode object. However, you still know that "else" will fall in the realm of 4xx or 5xx type error codes.
So I would update your original code to:
var statusCodeResponses = {
200: function () { //Employee_Company saved now updated
hideLoading();
ShowAlertMessage(SaveSuccessful, 2000);
$('#ManageEmployee').dialog('close');
},
304: function () { //Nothing to save to Employee_Company
hideLoading();
$('#ManageEmployee').dialog('close');
if (NothingToChange_Employee) {
ShowAlertMessage(NothingToUpdate, 2000);
} else {
ShowAlertMessage(SaveSuccessful, 2000);
}
}
};
var genericElseFunction = function(response){
// do whatever other action you wanted to take
};
for(var badResponseCode=400; badResponseCode<=599; badResponseCode++){
statusCodeResponses[badResponseCode] = genericElseFunction;
}
$.ajax({
type: 'POST',
contentType: "application/json",
url: "../API/Employees.svc/" + EmployeeId + "/Company/" + CompanyId,
data: jsonString,
statusCode: statusCodeResponses,
error: function (XMLHttpRequest, textStatus, errorThrown) {
AjaxError(XMLHttpRequest, textStatus, errorThrown);
}
});
I'm trying to catch Ajax timeout error with jQuery 1.4.2, but none of tutorial I found work. In Firebug, when timeout error fires. I see:
uncaught exception: [object Object].
Please help me handle Ajax timeout. Here's my JS code:
$.ajax({
type:"POST",
url:"/data/add/",
data:
{
"date":$("input#date").val();
},
dataType:"json",
timeout:2000,
success: function(response) {
},
error: function () {
alert('Server error');
}
});
I tested this out, and if you remove the ; from your $("input#date").val() statement, it should work.
$.ajax({
type:"POST",
url:"/data/add/",
data:
{
"date":$("input#date").val()
},
dataType:"json",
timeout:2000,
success: function(response) {
},
error: function () {
alert('Server error');
}
});
something went wrong again, and i got googled this f*****g bug http://dev.jquery.com/ticket/6173 ! here is the spike:
success: function(response, textStatus, xhr) {
if (!xhr.status) {
alert("ERROR!!!!");
}
else {
// elided
}
I want to make an Ajax request with response in JSON. So I made this Ajax request:
$.ajax({
url: 'http://my_url',
dataType: "json",
success: function(data){
alert('success');
},
error: function(data){
alert('error');
},
complete: function(data) {
alert('complete')
}})
This code works good but when my url send me a HTTP code 404, no callbacks are used, even the complete callback.
After research, it's because my dataType is 'json' so 404 return is HTML and the JSON parsing failed. So no callback.
Have you a solution to call a callback function when a 404 is raised ?
EDIT: complete callback don't call is return is 404. If you want an URL wit 404 you can call : http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697 it's with this URL I have my problem.
$.ajax({
url: 'http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697',
dataType: "json",
success: function(data) {
alert('success');
},
error: function(data) {
alert('error');
},
complete: function(xhr, data) {
if (xhr.status != 0)
alert('success');
else
alert('fail');
}
})
With your configuration jQuery uses jsonp to transport the data. This works by dynamically inserting a script element and setting the URL to the specified value. The data returned by the server is then evaluated as JavaScript - usually calling the provided callback. If the server returns a 404, the contents is obviously no JavaScript and the callback is never called. Some browsers support error handlers on the script tag, which are called in these situations. Unfortunately IE doens't support this. The best way to detect an error is to rely on a timeout.
In your case you should specify an additional timeout option, which causes the error handler to be called if the callback wasn't called in time (which would be the case for a 404 response).
$.ajax({
url: 'http://my_url',
timeout: 2000, // 2 seconds timeout
dataType: "json",
success: function(data){
alert('success');
},
error: function(data){
alert('error');
},
complete: function(data) {
alert('complete')
}
});
Use the statusCode-Option
$.ajax({
url: 'http://my_url',
dataType: "json",
statusCode: {
404: function() {
alert("I could not find the information you requested.");
}
},
success: function(data) {
alert('success');
},
error: function(data) {
alert('error');
},
complete: function(data) {
alert('complete');
}
})
If you want to handle errors when accessing the Twitter API with Javascript and jsonp you need to include the parameter suppress_response_codes in your request. This makes all responses from the Twitter API respond with a 200 OK response and include a error. Then you need to check if the response includes the error parameter or not.
$.ajax({
url: "https://api.twitter.com/1/users/show.json",
dataType: 'jsonp',
jsonp: "callback",
data: {
screen_name: "simongate1337",
suppress_response_codes: true // <- Important part
},
success: function(data) {
if(data.error) {
console.log("ERROR: "+data.error);
} else {
console.log("Success, got user " + data.screen_name);
}
}
});
Do not you think that the problem is not with the dataType but with cross-domain requests that you are not allowed to make?
The code below works as expected when you request data from the same domain and does not when you are making cross-domain requests:
function handle404(xhr){
alert('404 not found');
}
function handleError(xhr, status, exc) {
// 0 for cross-domain requests in FF and security exception in IE
alert(xhr.status);
switch (xhr.status) {
case 404:
handle404(xhr);
break;
}
}
function dumbRequest() {
var url = 'http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697';
url = 'http://twitter.com/';
url = '/mydata.json';
// url = 'mydata.json';
$.ajax(
{url: url,
dataType: 'json',
error: handleError}
);
}
Is it simply because the dataType is set to "json"? If so, try changing it to text and evaluate the JSON yourself:
$.ajax({
url: 'http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697',
dataType: 'text',
success: function(data, status, xmlHttp) {
try {
data = eval('(' + data + ')');
alert('success');
} catch (e) {
alert('json parse error');
}
},
error: function(xmlHttp, status, error) {
alert('error');
},
complete: function(xmlHttp, status) {
alert('complete');
}
});
Are you aware that even though the HTTP status is 404, the actual body is valid JSON? For instance, this link has the following JSON:
jsonp1269278524295({"request":"/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697","error":"Not found"})
As such, you should check if your data has the error property within your normal callback function.
UPDATE: apparently, even though the actual content of the page is valid JSON, the browser (I checked in Firefox) is not executing it, most likely because it is a 404. Because jQuery has to add a script element (because of the cross-domain issue), its JSONP wrapper is never called, and as a consequence, neither are your callbacks.
So, in short, I don't think there is a way to deal with this without manually adding that script element and checking if your pre-defined callback function has been called afterwards.
Just faced the same issue, and saw another question mentioned that jQuery-JSONP (jQuery Plugin) supports catching 404 errors or as they describe: "error recovery in case of network failure or ill-formed JSON responses"
And it works perfect :)
Here is my (simplified) code for fetching details about a YouTube video via JSONP:
$.jsonp(
{
url: "https://gdata.youtube.com/feeds/api/videos/ee925OTFBCA",
callbackParameter: "callback",
data:
{
alt: "jsonc-in-script",
v: "2"
},
success: function(json, textStatus)
{
console.log("WEEEEEEEE!");
},
error: function(xOptions, textStatus)
{
console.error(arguments);
}
});
Here's how I deal with this. I check the returned data for errors before trying to use it. What is shown below is just a sample that you could extend to more closely match your requirements. This also considers session time outs and other scenarios...
My initial call:
$.ajax({ type: 'POST',
url: '../doSomething',
data: 'my data',
success: function(data) {
if (HasErrors(data)) return;
var info = eval('(' + data + ')');
// do what you want with the info object
},
error: function(xmlHttpRequest) {
ReportFailure(xmlHttpRequest);
}
});
And the two helper functions:
function HasErrors(data) {
if (data.search(/login\.aspx/i) != -1) {
// timed out and being redirected to login page!
top.location.href = '../login.aspx';
return true;
}
if (data.search(/Internal Server Error/) != -1) {
ShowStatusFailed('Server Error.');
return true;
}
if (data.search(/Error.aspx/) != -1) {
// being redirected to site error reporting page...
ShowStatusFailed('Server Error. Please try again.');
return true;
}
return false;
}
and
function ReportFailure(msg) {
var text;
if (typeof msg == 'string') {
text = msg;
}
else if (typeof msg.statusText == 'string') {
if (msg.status == 200) {
text = msg.responseText;
}
else {
text = '(' + msg.status + ') ' + msg.statusText + ': ';
// use the Title from the error response if possible
var matches = msg.responseText.match(/\<title\>(.*?)\<\/title\>/i);
if (matches != null)
{ text = text + matches[1]; }
else
{ text = text + msg.responseText; }
}
}
// do something in your page to show the "text" error message
$('#statusDisplay')
.html('<span class="ui-icon ui-icon-alert"></span>' + text)
.addClass('StatusError');
}
Following solution is working fine for me :)
$.ajax({
url: 'http://my_url',
dataType: "json",
success: function(data){
alert('success');
},
error: function(data){
alert('error');
},complete: function(xhr, data) {
if(data==="parsererror"){
alert('404');
}
}
});