Globally configure all $.ajax requests to support retry on timeout - javascript

I need a way to set some kind of timeout function globally with $.ajaxSetup that will allow my Phonegap application to keep retrying an ajax GET or POST every time there is a timeout due to a bad internet connection.
I use Backbone.js so most jquery plugins won't work for this, I would some help writing one global piece of code which will handle retries.
Thank you.

You can use jQuery.ajaxSetup(options).
Set default values for future Ajax requests. Its use is not recommended.
Example
$.ajaxSetup({
timeout: TimeoutValue
});
Apart from that if you want perform call again on timeout, I will suggest you to create wrapper for ajax call like.
function myAjax(options){
var myOptions = {
timeout: TimeoutValue,
error: function( jqXHR, textStatus, errorThrown) {
//textStatus can one of these "timeout", "error", "abort", and "parsererror"
if(textStatus === "timeout") {
//Recall method once again
myAjax(options)
}
}
};
options = $.extend(true, myOptions , options);
$.ajax(options)
}
And Use the function just like $.ajax

Found a solution to make all AJAX calls work with a retry timeout.
$(document).ajaxError(function (e, xhr, options) {
if(xhr.status == 0){
setTimeout(function(){
console.log('timeout, retry');
$.ajax(options);
}, 5000);
}
});

Related

Javascript: Adding timeout to synchronous REST API call

I'm going to call a function which makes a Synchronous REST API call. I want to somehow timeout on that function call if it does not return within some time. How do I do that?
callBlahService = function(args){
// make actual rest api call
$.ajax{
// arguments
async: false
}
}
callBlahService({
success:function(data){
console.log("blah successful");
},
error: function(data){
console.log("blah failed");
}
});
Looks like you're using JQuery. There is a timeout setting on $.ajax that should be use: http://api.jquery.com/jQuery.ajax/
Your error handler will get called if the timeout is exceeded.
$.ajax({
timeout: 1000,
success: function(response) {},
error: function(x, t, m) {
if(t==="timeout") {
alert("timed out!");
}
}
});​
timeout
Type: Number
Set a timeout (in milliseconds) for the request. This will override any global timeout set with $.ajaxSetup(). The timeout period starts at the point the $.ajax call is made; if several other requests are in progress and the browser has no connections available, it is possible for a request to time out before it can be sent. In jQuery 1.4.x and below, the XMLHttpRequest object will be in an invalid state if the request times out; accessing any object members may throw an exception. In Firefox 3.0+ only, script and JSONP requests cannot be cancelled by a timeout; the script will run even if it arrives after the timeout period.
http://api.jquery.com/jQuery.ajax/

How to detect Ajax call failure due to network disconnected

I am sending lots of data using jquery ajax method to web sever and client side respond only after receiving acknowledgment from server, now suppose network connection lost in MIDDLE of ajax call then how to detect this situation.
$.ajax({
url:'server.php',
data:'lots of data from 200KB to 5MB',
type:'post',
success: function(data)
{
alert('Success');
//some stuff on success
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert('Failure');
//some stuff on failure
}
});
This is my code and and it does not give error in middle of ajax call if get internet is disconnected.
NOTE : I cant use time out because data size is vary from 200kb to 5MB and server response time calculation is not feasible.
Try this:
First create a "ping" ajax call with setInterval every 5 seconds
function server_ping()
{
$.ajax({
url:"url to ping",
type: "POST"
});
}
var validateSession = setInterval(server_ping, 5000);
then arm your .ajaxError trap:
$(document).ajaxError(function( event, request, settings ) {
//When XHR Status code is 0 there is no connection with the server
if (request.status == 0){
alert("Communication with the server is lost!");
}
});
Remember Ajax calls are Asynchronous by default, so when the pings are going to the server and the request cannot reach the server the value on the XHR status is 0, and the .ajaxError will fire and you must catch the error and handle the way you want it.
Then you can send your data to the server, if the connection is lost when sending the data you get the error reported by the ping.
If your server was not very crowded, probably you could use a timer to start detecting the connection regularly when you start transferring the data (by using another ajax calling, for instance each 5 seconds). now you can use timeout.
Btw,
1)timeout doesn't always means network error. sometimes server's down also causes "timeout"
2)if the driver is down on client device, xhr.status = 0, and no timeout
I had a similar problem and solved it with a simpel try/catch and a re-try delay of (say) 2 seconds:
function myAjaxMethod()
{
try
{
$.ajax({ ... });
} catch (err)
{
console.log(err.message);
setTimeout(function(){myAjaxMethod(),2000});
}
}
I faced a similar situation like yours and fixed it by having a network check for every 5 seconds and if network is disconnected i would abort the ajax request manually which will end the ajax request.
Here i get the ajax XmlHttpRequest in the beforeSend event of the Jquery ajax call and use that object to abort the ajax request in case of network failure.
var interval = null;
var xhr = null;
$.ajax({
beforeSend: function(jqXHR, settings) {
xhr = jqXHR; // To get the ajax XmlHttpRequest
},
url:'server.php',
data:'lots of data from 200KB to 5MB',
type:'post',
success: function(data)
{
alert('Success');
//some stuff on success
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert('Failure');
//some stuff on failure
},
complete: function(data)
{
alert('Complete');
//To clear the interval on Complete
clearInterval(interval);
},
});
interval = setInterval(function() {
var isOnLine = navigator.onLine;
if (isOnLine) {
// online
} else {
xhr.abort();
}
}, 5000);
Try adding timeout: while constructing your $.ajax({}).
Also make sure to set cache: false, helpful sometimes.
Refer to Jquery's ajax() : http://api.jquery.com/jQuery.ajax/#toptions
You will get much more information there!
My thought s on your problem[updated]
#RiteshChandora , I understand your concern here. How ever I can suggest you to do 2 things.
As you have post data ranging from 200kb to 5mb, you might want to choose a maximum timeout. and trigger for the same. Yes, this might be problematic, but with the design you chosen, the only way to monitor the POST progress is to do this way. if not, see point 2.
I went through the flow, you are asking the user to copy the response Json from FB to your url. there are some problems here,
The json data has sensitive information about the user, and he is posting it on a url without SSL encryption.
Why should you prompt the user to post the acquired data on to your server? it should be easier if you user sever side scripts. Also you should never post huge data from the client to the server in occasions like these, where you could retrieve the same form the FBserver->your sevrer on the server side.
My suggested solution : after the user is authenticated , retrieve his friends list on the server side. do whatever you want on the server side, and display the result on the users screen.
This way all the burden will be taken by your server, also there is no need for the user to do any nasty json posting on your url.
Btw, your app idea is cool.
error: function(xhr, textStatus, thrownError)
{
alert(xhr.status);
alert(thrownError);
alert(textStatus);
}
Try them..
TextStatus (besides null) are "timeout", "error", "abort", and "parsererror".
When an HTTP error occurs, thrownError receives the textual portion of the HTTP status, such as "Not Found" or "Internal Server Error."
If Internet disconnects,the response wont be received and maximum it would be a timeout message..

How to find the ajax status with jQuery 1.2.6

I'm using jQuery 1.2.6 (I know it's old, but I don't have a choice) I need to check the status of my ajax calls. I either want to use:
statusCode, or I could even use error(jqXHR, textStatus, errorThrown), except that textStatus, errorThrown and statusCode, aren't in my jQuery version.
Basically what I have to do, is know if the ajax call was aborted, or had an error for another reason. Any ideas how I can do this?
you could get the status text from the error callback:
$.ajax({
url: "/foo",
dataType: "text",
error: function(obj){
alert(obj.status + "\n" + obj.statusText);
}
});
http://jsfiddle.net/jnXQ4/
you can also get it from the complete callback if the request resulted in an error.
Edit: the ajax request also returns the XMLHttpRequest which you can then bind events to, though I'm not sure how cross-browser it is.
var request = $.ajax(options);
request.onabort = function(){
alert('aborted');
}

jQuery AJAX fires error callback on window unload - how do I filter out unload and only catch real errors?

If I navigate away from a page in the middle of an $.ajax() request it fires the error callback. I've tested in Safari and FF with both GET and POST requests.
One potential solution would be to abort all AJAX requests on page unload, but the error handler is called before unload, so this doesn't seem possible.
I want to be able to handle REAL errors such as 500s gracefully on the client side with a polite alert or a modal dialog, but I don't want this handling to be called when a user navigates away from the page.
How do I do this?
--
(Also strange: When navigating away from a page, the error handler says that the textStatus parameter is "error", the same it throws when receiving a 500/bad request.)
In the error callback or $.ajax you have three input arguments:
function (XMLHttpRequest, textStatus, errorThrown) {
this; // options for this ajax request
}
You can check directly the xhr.status to get the HTTP response code, for example:
$.ajax({
url: "test.html",
cache: false,
success: function(html){
$("#results").append(html);
},
error: function (xhr, textStatus) {
if (xhr.status == 500) {
alert('Server error: '+ textStatus);
}
}
});
Edit:
To tell the difference between a connection broken by the browser and the case where the server is down (jasonmerino's comment):
On unload the xhr.readyState should be 0, where for a non responsive
server the xhr.readyState should be 4.
This is a tough one to handle correctly in all situations. Unfortunately in many popular browsers the xhr.status is the same (0) if the AJAX call is cancelled by navigation or by a server being down / unresponsive. So that technique rarely works.
Here's a set of highly "practical" hacks that I've accumulated that work fairly well in the majority of circumstances, but still isn't bullet-proof. The idea is to try to catch the navigate events and set a flag which is checked in the AJAX error handler. Like this:
var global_is_navigating = false;
$(window).on('beforeunload',function() {
// Note: this event doesn't fire in mobile safari
global_is_navigating = true;
});
$("a").on('click',function() {
// Giant hack that can be helpful with mobile safari
if( $(this).attr('href') ) {
global_is_navigating = true;
}
});
$(document).ajaxError(function(evt, xhr, settings) {
// default AJAX error handler for page
if( global_is_navigating ) {
// AJAX call cancelled by navigation. Not a real error
return;
}
// process actual AJAX error here.
});
(I'd add this as a comment to the main answer but haven't built up enough points to do so yet!)
I'm also seeing this in FF4 and Chrome (9.0.597.107). Probably elsewhere but that's bad enough for me to want to fix it!
One of the things that's odd about this situation is that returned XMLHttpRequest.status === 0
Which seems like a reliable way to detect this situation and, in my particular case, abort the custom error handling that displays to the user:
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (XMLHttpRequest.status === 0) return;
// error handling here
}
Also worth mentioning that on the assumption if may be a problem in the JSON parse of whatever the browser is giving back to the $.ajax() call, I also tried swapping out the native JSON.stringify for the Douglas Crockford version ( https://github.com/douglascrockford/JSON-js ) but that made no difference.
The error callback should get a reference to the XHR object, check the status code to see if it's a server error or not?
If you make use of jQuery functions such as $.get, $.post, $.ajax... then you can use the parameter text_status to check what type of fail is:
request = $.get('test.html', function(data){
//whatever
}).fail(function(xhr, text_status, error_thrown) {
if(text_status!== 'abort'){
console.warn("Error!!");
}
});
From the jQuery docs:
jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {}); An alternative construct to the error callback option, the .fail() method
replaces the deprecated .error() method. Refer to deferred.fail() for
implementation details.
Just wait a while before showing the error. If a request fails due to page unload, the timeout won't fire and the error won't be shown. My experiments have shown that 100ms is enough for desktop Safari and Firefox (desktop and Android) and 500ms is enough for iOS Safari. The durations are fuzzy, so you should increase the numbers if it's possible.
const request = new XMLHttpRequest();
// Firefox calls onabort, Safari calls onerror
request.onabort = request.onerror = () => {
// A short comprehensive solution
setTimeout(() => {
alert('The request has failed completely');
}, 500);
// A more gentle solution
const isWebKit = 'ApplePayError' in window;
const isDesktopSafari = !('standalone' in navigator);
const isGecko = 'mozInnerScreenX' in window
setTimeout(
() => {
alert('The request has failed completely');
},
isWebKit ? (isDesktopSafari ? 100 : 500) : (isGecko ? 100 : 0)
);
}
request.open('get', 'http://example.com', true);
request.send();
I've checked this solutions only in modern browsers (Chrome 87, Firefox 83, IE 11, Edge, Safari 14).

How do I catch jQuery $.getJSON (or $.ajax with datatype set to 'jsonp') error when using JSONP?

Is it possible to catch an error when using JSONP with jQuery? I've tried both the $.getJSON and $.ajax methods but neither will catch the 404 error I'm testing. Here is what I've tried (keep in mind that these all work successfully, but I want to handle the case when it fails):
jQuery.ajax({
type: "GET",
url: handlerURL,
dataType: "jsonp",
success: function(results){
alert("Success!");
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Error");
}
});
And also:
jQuery.getJSON(handlerURL + "&callback=?",
function(jsonResult){
alert("Success!");
});
I've also tried adding the $.ajaxError but that didn't work either:
jQuery(document).ajaxError(function(event, request, settings){
alert("Error");
});
Here's my extensive answer to a similar question.
Here's the code:
jQuery.getJSON(handlerURL + "&callback=?",
function(jsonResult){
alert("Success!");
})
.done(function() { alert('getJSON request succeeded!'); })
.fail(function(jqXHR, textStatus, errorThrown) { alert('getJSON request failed! ' + textStatus); })
.always(function() { alert('getJSON request ended!'); });
It seems that JSONP requests that don't return a successful result never trigger any event, success or failure, and for better or worse that's apparently by design.
After searching their bug tracker, there's a patch which may be a possible solution using a timeout callback. See bug report #3442. If you can't capture the error, you can at least timeout after waiting a reasonable amount of time for success.
Detecting JSONP problems
If you don't want to download a dependency, you can detect the error state yourself. It's easy.
You will only be able to detect JSONP errors by using some sort of timeout. If there's no valid response in a certain time, then assume an error. The error could be basically anything, though.
Here's a simple way to go about checking for errors. Just use a success flag:
var success = false;
$.getJSON(url, function(json) {
success = true;
// ... whatever else your callback needs to do ...
});
// Set a 5-second (or however long you want) timeout to check for errors
setTimeout(function() {
if (!success)
{
// Handle error accordingly
alert("Houston, we have a problem.");
}
}, 5000);
As thedawnrider mentioned in comments, you could also use clearTimeout instead:
var errorTimeout = setTimeout(function() {
if (!success)
{
// Handle error accordingly
alert("Houston, we have a problem.");
}
}, 5000);
$.getJSON(url, function(json) {
clearTimeout(errorTimeout);
// ... whatever else your callback needs to do ...
});
Why? Read on...
Here's how JSONP works in a nutshell:
JSONP doesn't use XMLHttpRequest like regular AJAX requests. Instead, it injects a <script> tag into the page, where the "src" attribute is the URL of the request. The content of the response is wrapped in a Javascript function which is then executed when downloaded.
For example.
JSONP request: https://api.site.com/endpoint?this=that&callback=myFunc
Javascript will inject this script tag into the DOM:
<script src="https://api.site.com/endpoint?this=that&callback=myFunc"></script>
What happens when a <script> tag is added to the DOM? Obviously, it gets executed.
So suppose the response to this query yielded a JSON result like:
{"answer":42}
To the browser, that's the same thing as a script's source, so it gets executed. But what happens when you execute this:
<script>{"answer":42}</script>
Well, nothing. It's just an object. It doesn't get stored, saved, and nothing happens.
This is why JSONP requests wrap their results in a function. The server, which must support JSONP serialization, sees the callback parameter you specified, and returns this instead:
myFunc({"answer":42})
Then this gets executed instead:
<script>myFunc({"answer":42})</script>
... which is much more useful. Somewhere in your code is, in this case, a global function called myFunc:
myFunc(data)
{
alert("The answer to life, the universe, and everything is: " + data.answer);
}
That's it. That's the "magic" of JSONP. Then to build in a timeout check is very simple, like shown above. Make the request and immediately after, start a timeout. After X seconds, if your flag still hasn't been set, then the request timed out.
I know this question is a little old but I didn't see an answer that gives a simple solution to the problem so I figured I would share my 'simple' solution.
$.getJSON("example.json", function() {
console.log( "success" );
}).fail(function() {
console.log( "error" );
});
We can simply use the .fail() callback to check to see if an error occurred.
Hope this helps :)
If you collaborate with the provider, you could send another query string parameter being the function to callback when there's an error.
?callback=?&error=?
This is called JSONPE but it's not at all a defacto standard.
The provider then passes information to the error function to help you diagnose.
Doesn't help with comm errors though - jQuery would have to be updated to also callback the error function on timeout, as in Adam Bellaire's answer.
Seems like this is working now:
jQuery(document).ajaxError(function(event, request, settings){
alert("Error");
});
I use this to catch an JSON error
try {
$.getJSON(ajaxURL,callback).ajaxError();
} catch(err) {
alert("wow");
alert("Error : "+ err);
}
Edit: Alternatively you can get the error message also. This will let you know what the error is exactly. Try following syntax in catch block
alert("Error : " + err);
Mayby this works?
.complete(function(response, status) {
if (response.status == "404")
alert("404 Error");
else{
//Do something
}
if(status == "error")
alert("Error");
else{
//Do something
}
});
I dont know whenever the status goes in "error" mode. But i tested it with 404 and it responded
you ca explicitly handle any error number by adding this attribute in the ajax request:
statusCode: {
404: function() {
alert("page not found");
}
}
so, your code should be like this:
jQuery.ajax({
type: "GET",
statusCode: {
404: function() {
alert("page not found");
}
},
url: handlerURL,
dataType: "jsonp",
success: function(results){
alert("Success!");
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Error");
}
});
hope this helps you :)
I also posted this answer in stackoverflow - Error handling in getJSON calls
I know it's been a while since someone answerd here and the poster probably already got his answer either from here or from somewhere else. I do however think that this post will help anyone looking for a way to keep track of errors and timeouts while doing getJSON requests. Therefore below my answer to the question
The getJSON structure is as follows (found on http://api.jqueri.com):
$(selector).getJSON(url,data,success(data,status,xhr))
most people implement that using
$.getJSON(url, datatosend, function(data){
//do something with the data
});
where they use the url var to provide a link to the JSON data, the datatosend as a place to add the "?callback=?" and other variables that have to be send to get the correct JSON data returned, and the success funcion as a function for processing the data.
You can however add the status and xhr variables in your success function. The status variable contains one of the following strings : "success", "notmodified", "error", "timeout", or "parsererror", and the xhr variable contains the returned XMLHttpRequest object
(found on w3schools)
$.getJSON(url, datatosend, function(data, status, xhr){
if (status == "success"){
//do something with the data
}else if (status == "timeout"){
alert("Something is wrong with the connection");
}else if (status == "error" || status == "parsererror" ){
alert("An error occured");
}else{
alert("datatosend did not change");
}
});
This way it is easy to keep track of timeouts and errors without having to implement a custom timeout tracker that is started once a request is done.
Hope this helps someone still looking for an answer to this question.

Categories