I have multiple ajax requests some request data every minute others are initiated by the user through a ui.
$.get('/myurl', data).done(function( data ){
// do stuff..
});
The request might fail due to an authentication failure.
I've setup a global .ajaxError() method for catching any failed requests.
$(document).ajaxError(function( e, jqxhr ){
// Correct error..
});
After I catch the error I reset authorization.
Resetting the authorization works but the user has to manually re initiate the ajax call (through the ui).
How do I resend the failed request using the jqxhr originally sent?
(I'm using jQuery for the ajax)
Found this post that suggests a good solution to this problem.
The main thing is to use $.ajaxPrefilter and replace your error handler with a custom one that checks for retries and performs a retry by using the closure's 'originalOptions'.
I'm posting the code just in case it will be offline in the future. Again, the credit belongs to the original author.
// register AJAX prefilter : options, original options
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
originalOptions._error = originalOptions.error;
// overwrite error handler for current request
options.error = function( _jqXHR, _textStatus, _errorThrown ){
if (... it should not retry ...){
if( originalOptions._error ) originalOptions._error( _jqXHR, _textStatus, _errorThrown );
return;
};
// else... Call AJAX again with original options
$.ajax( originalOptions);
};
});
In this case, I would write a specific handler for the 403 status code, which means unauthorized (my server would return a 403 too). From the jquery ajax docs, you can do
$.ajax({
statusCode: {
403: function() {
relogin(onSuccess);
}
}
});
to achieve that.
In that handler, I would call a relogin method, passing a function that captures what to do when login succeeds. In this case, you could pass in the method that contains the call you want to run again.
In the code above, relogin should call the login code, and onSuccess should be a function that wraps the code you execute every minute.
EDIT- based on your clarification in comment, that this scenario happens for multiple requests, I personally would create an API for your app that captures the interactions with the server.
app = {};
app.api = {};
// now define all your requests AND request callbacks, that way you can reuse them
app.api.makeRequest1 = function(..){..} // make request 1
app.api._request1Success = function(...){...}// success handler for request 1
app.api._request1Fail = function(...){...}// general fail handler for request 1
/**
A method that will construct a function that is intended to be executed
on auth failure.
#param attempted The method you were trying to execute
#param args The args you want to pass to the method on retry
#return function A function that will retry the attempted method
**/
app.api.generalAuthFail = function(attempted, args){
return function(paramsForFail){ // whatever jquery returns on fail should be the args
if (attempted) attempted(args);
}
}
so with that structure, in your request1 method you would do something like
$().ajax({
....
statusCode: {
403: app.api.generalAuthFail(app.api.request1, someArgs);
}
}}
the generalAuthFailure will return a callback that executes the method you pass in.
The code below will keep the original request and it will try to success 3 times.
var tries = 0;
$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
if(tries < 3){
tries++;
$.ajax(this).done(function(){tries=0;});
}
});
You could possibly go by the option of naming each one of your functions and then recalling them as stated in hvgotcodes' answers.
Or
You can use a reusable function to setup a request while extending the defaults:
function getRequest( options ){
var // always get json
defaults = { dataType: 'json' },
settings = $.extend( defaults, options );
return // send initial ajax, if it's all good return the jqxhr object
$.ajax( settings )
// on error
.fail(function( jqxhr, e ){
// if the users autherization has failed out server responds with a 401
if( jqxhr.status === 401 ){
// Authenticate user again
resetAuthentication()
.done(function(){
// resend original ajax also triggering initial callback
$.ajax( settings );
});
}
});
};
To use the above function you would write something like this:
getRequest({
url: 'http://www.example.com/auth.php',
data: {user: 'Mike', pass: '12345'},
success: function(){ // do stuff }
});
The getRequest() could probably be made recursive and/or converted into a jQuery plugin but this was sufficient for my needs.
Note: If the resetAutentication function might faile, getRequest() would have to be recursive.
Related
Send through ajax each element from the following array. Note: Each request must
be made once the previous has finished.
[‘This’, ‘is’, ‘a’, ‘fake, ‘array’]
I am a little confused by this question because I thought Ajax is asynchronous, meaning the script keeps sending requests to the server without waiting for the reply.
***Was downvoted so going to clarify something: It specifically states in the problem statement that the REQUEST must be made synchronously. I do realize that there are better ways of doing this via def/promises asynchronously so order remains for the result but that isn't the request.
Ajax has a async parameter you can set to false which will block until call completion.
Per documentation:
async (default: true)
Type: Boolean
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done().
http://api.jquery.com/jquery.ajax/
Example:
$.each(["This", "is", "a", "fake", "array"], function( index, value ) {
$.ajax({
type: 'POST',
dataType: 'json',
url: '/echo/json/',
data : { json: JSON.stringify( value ) },
async: false,
success: function(data) { alert(data);}
});
});
Working fiddler example: https://jsfiddle.net/zm9bb4xk/
I was talking about JQuery Ajax.
So, first, based on documentation, Ajax has many events that run at certain times, for example:
beforeSend (Local Event)
This event, which is triggered before an Ajax request is started,
allows you to modify the XMLHttpRequest object (setting additional
headers, if need be.)
error (Local Event)
This event is only called if an error occurred with the request (you
can never have both an error and a success callback with a request).
complete (Local Event)
This event is called regardless of if the request was successful, or
not. You will always receive a complete callback, even for synchronous
requests.
success (Local Event)
This event is only called if the request was successful (no errors
from the server, no errors with the data).
More in documentation.
Second, following your example (you have to complete this with your own data and this code is not tested, maybe it has some small sintax errors), an approximation is:
// Variables
var myArray = ["This", "is", "a", "fake", "array"];
var globalIndex = 0;
// Function for Ajax Calls
function myFunction(){
$.ajax({
url: 'myURL', // Your own controller/url
type: "GET", // Or POST
dataType: "json", // Or other datatype
data: {
arrayContent: myArray[globalIndex] // arrayContent = your controller param name
},
/**
* A function to be called if the request succeeds.
*/
success: function(data) {
alert('Load was performed. Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information! ');
alert(data); // Do what you want with your data, this is an example
globalIndex = globalIndex +1;
// Recursive/next call if current call is finished OK and there are elements
if(globalIndex < myArray.length){
myFunction();
}
},
/**
* A function to be called if the request fails.
*/
error: function(jqXHR, textStatus, errorThrown) {
alert('An error occurred... Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information!');
alert('<p>status code: '+jqXHR.status+'</p><p>errorThrown: ' + errorThrown + '</p><p>jqXHR.responseText:</p><div>'+jqXHR.responseText + '</div>');
console.log('jqXHR:');
console.log(jqXHR);
console.log('textStatus:');
console.log(textStatus);
console.log('errorThrown:');
console.log(errorThrown);
// We don't do a recursive/next call because current call has failed
},
});
}
// First call to myFunction
myFunction();
I am learning to use jQuery Ajax. What does function(response) mean and what is the meaning of response == 1 and response == 2?
jQuery.post(ajaxurl, data, function(response) {
if (response == 1) {
$saveAlert.addClass('is-success').delay(900).fadeOut(700);
setTimeout(function() {
$tieBody.removeClass('has-overlay');
}, 1200);
} else if (response == 2) {
location.reload();
} else {
$saveAlert.addClass('is-failed').delay(900).fadeOut(700);
setTimeout(function() {
$tieBody.removeClass('has-overlay');
}, 1200);
}
});
I'll explain the basics:
jQuery.post = You want to post some data to your endpoint
ajaxurl = your endpoint address. Typically a API
data = the data you want to send to your endpoint along with the request.
function(response) is where you handle the response from the endpoint.
So lets go through the code. First you call post to your endpoint / API with the data you want to post. Then you provide a callback (in your case a function) to handle the response the endpoint / API provides you.
In your case it looks like if the endpoint responds with 1, you have successfully posted your data. If the endpoint responds with 2, you have posted data and want to reload the site. If the endpoint does NOT respond with either 1 or 2, it failed to post.
To help you understand the basics of jQuery post:
A well-written API / endpoint should respond with the correct HTTP status codes and status messages and it should be fairly easy to notice when data was posted correctly and when an error occurred.
I don't think your endpoint responds any good. response == 1 or response == 2is not by any means clear and easy to understand.
A better way of handling success and errors is to use the done and fail handlers of jquery post (more on this below).
$.post( "test.php" );
This will completely ignore the response from calling the endpoint. I.e. you don't want to handle either success or error. PLEASE DO NOT USE THIS. You should handle success and error!
$.post( "test.php", function( data ) {
//Do something now
});
This will do whatever you provide in the function when the endpoint has sent its response.
$.post( "example.php", function() {
//You successfully reached the endpoint
console.log( "success" );
})
.done(function() {
//Handle success here!
})
.fail(function() {
//Handle error here
})
This is probably the preferred way of handling both success and errors. It's pretty clear that if you reach the fail, it has failed. Both easy to read the code and easy to understand jquery post!
The examples above is copied from the jquery documentation.
Note that the previous handlers for done and fail was success and error, but success and error is deprecated and removed in jQuery 3.0!
So if you have jQuery version < 3.0 you need to find out if you need to use the new or old syntax, or if you need to update jQuery maybe?
Hope this explains enough to make you understand the basics, and to help you get further. I highly suggest you read the jQuery.post documentation here. I think you should also read the w3schools documentation here.
I have a form I am submitting with $.post() in jquery..
$.post("testpage.php", $("#payment-form").serialize())
The post works fine itself, but when the post is done and successful the page will do other stuff such as display a thank you message and stuff. I just need to where to put to call to display the message.I do not understand where it goes in terms of the success being returned from the post.
You can specify a 3rd argument to .post() that is the "success" callback. It is a function to call when the .post execution is successful.
$.post("testpage.php", $("#payment-form").serialize(), function() { alert('post was successful!')})
Source: http://api.jquery.com/jquery.post/
In short, like this:
$.post("testpage.php", $("#payment-form").serialize(), function () {
// Start partying here.
}).fail(function() {
// Handle the bad news here.
})
Alternatively, you can use deferred objects, like as follow:
// Create POST request
var paymentPost = $.post("testpage.php", $("#payment-form").serialize());
// Assigned deferred objects
// "data" refers to the data, preferably in JSON format, returned by testpage.php
paymentPost
.done(function(data) {
// Success
// e.g. display thank you message, redirect to a payment successful page...
})
.fail(function(data) {
// If error
// e.g. display error message(s)
})
.always(function() {
// Will always fire as long as POST request is submitted and completed
});
p/s: It is important to note that jqXHR methods like .success() and .error() are deprecated. To prepare for their eventual removal, you should abide to the new nomenclature for deferred objects ;)
Question
I wanna set a ajax setting for global ajax handled by jQuery
Condition:
If ajax url is 'www.example.com', the data (querystring or body) will append token.
I tried two method
.ajaxPrefilter
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
// Add data to ajax option
if (options.url.match(/www\.example\.com/i) !== null) {
originalOptions.data.token = 'i_am_token'
}
});
To add token when url is www.example.com-> it not work!
In console/debugger originalOptions Object is added token property,
but request sent not having token parameter
.ajaxSetup / beforeSend Event
$.ajaxSetup({
beforeSend: function(jqXHR, settings) {
// Only GET Method
if (settings.url.match(/www\.example\.com/i) == null){
settings.url.replace(/((\.\/[a-z][0-9])*\?+[=%&a-z0-9]*)&?token=[a-z0-9]*&?([=%&a-z0-9]*)/gi, "$1$3")
}
},
data: {
token: 'i_am_token'
}
});
And a reverse resolution, add token for each ajax request.
Same as last one, settings.url changed by string replace in the console/debugger.
But request still sent original url.
Test in jsfiddle: http://jsfiddle.net/qVLN2/2/
Thanks for your reading and help :)
You should notice that the String.replace function doesn't affect the original string!
You can try using settings.url = settings.url.replace(....); in your code.
EXT JS - I would like to know how to check the json response for a session time out like if a user is idle for say 20 minutes or so if his session is expired or not
There is no standard way of handling session timeouts in ExtJS. ExtJS is a client-side library, used to create the user interface/front-end layer of an application, while session management takes place on the server side.
ExtJS Ajax requests implement a callback mechanism. It means that a certain Javascript function is assigned as the callback function, which is called when the Ajax request has finished (either successfully or unsuccessfully). Here's an example taken from ExtJS API Documentation - see parameters success and failure that define the callback functions:
// Basic request
Ext.Ajax.request({
url: 'foo.php',
success: someFn,
failure: otherFn,
headers: {
'my-header': 'foo'
},
params: { foo: 'bar' }
});
So, in the case of session timeout, you could (for example) construct a JSON response, which would contain some error code (defined by you), and an error message to be shown to the user. The callback function should then check if this error is returned from the server, and take necessary actions (show error message, redirect to login page, etc.) when that happens.
Note that in the above case, from ExtJS viewpoint, the Ajax request would actually be successful. When the HTTP request fails altogether (HTTP errors like 403 and such), the Ajax request is considered unsuccessful. This is important because it is usually possible to define different callback functions for successful and unsuccessful requests (as in the above sample code).
You can mock the timeout session...
var keepaliveHandler = new Ext.util.DelayedTask(function(){
Ext.Ajax.request({
url : '/keepalive',
method : 'GET',
success: function(response, options){
//dummy server call each 60 seconds
keepaliveHandler.delay(60000);
}
});
});
var timeoutHandler = new Ext.util.DelayedTask(function(){
//invalidate session
Ext.Ajax.request({
url : '/logout',
method : 'GET',
success: function(response, options){
Ext.MessageBox.show({
title: MessagesMap.getMessage('session.closed'),
msg: MessagesMap.getMessage('session.closed.message'),
buttons: Ext.MessageBox.OK,
fn: function() {
window.location.pathname = '/';
},
icon: Ext.MessageBox.WARNING
});
}
});
});
if(Ext.ux.SystemProperties.isLogged) {
keepaliveHandler.delay(60000);
timeoutHandler.delay(Ext.ux.SystemProperties.timeout);
//check for mouse movements
document.body.onmousemove = function(e) {
timeoutHandler.delay(Ext.ux.SystemProperties.timeout);
};
}