Strategies for handling session timeout?
Strategies for handling session timeout?
Apologies for the long question; this is half "how do I get this to work," and half "do I even want this to work?"
I have a case where this is happening:
- the user logs in, loads a page with a DataTable, & brings up one or more records in Editor
- they wander off; their session times out
- they come back and hit submit
- the server sends back an HTTP 302 redirect to the login page (and the login page is being requested; more on this below)
- Editor displays "A system error has occurred" as the error message, with a "more information" link to datatables.net
My first thought was that I wanted to display a more helpful error message ("Dude, you need to change your fiber intake" or whatever). However, it turns out that things are actually a little more complicated than that: some of my Editor fields use dependent
to rebuild option lists when their values change (e.g., if you're trying to assign Necrobutcher a role in a black metal band, and you choose Mayhem as the band, I fetch Mayhem's list of available roles, which will have Lead Keytar filtered out on the server side), and those ajax calls are getting 302s (followed by 200s as the browser--or jQuery?--succesfully requests the login page from the redirect, and then my code croaks when it gets the HTML login page instead of the JSON list of roles).
So, in some cases, life may be bad before they hit submit, so wanting to handle the 302 in Editor's "submit" ajax call may be fundamentally misguided. How are other people handling this sort of thing?
If it turns out that the "submit" ajax call is the right place to handle the 302, I see this question which gives an example of handling an error by calling alert()
and then notifying Editor, and I see the ajax
documentation explaining how to use a function instead of an object, but I'm having trouble getting it working.
Here's what I've got currently, before making any changes.
// this guy is in a file which is shared by all my DataTables pages
var editorAjax = function( url ) {
return {
'url': url,
contentType: 'application/json',
data: function ( d ) {
return JSON.stringify( d );
}
};
};
// this is how I'm calling that in my various tables/pages
editor = new $.fn.dataTable.Editor( {
ajax: editorAjax( '/my/nifty/api' ),
table: '#my_nifty_table',
...
Adding an error
element to that object returned by my editorAjax()
function looks like this:
var editorAjax = function( url ) {
return {
'url': url,
contentType: 'application/json',
data: function ( d ) {
return JSON.stringify( d );
},
error: function ( xhr, jqAjaxerror, thrown ) {
if ( xhr.status == 302 ) {
// call error() on my editor instance, once I get my
// hands on it? (It doesn't exist at this point;
// editorAjax() is called on the way in to the Editor
// constructor.)
}
// what else do I need to do in here?
}
};
};
The main problem here is that this doesn't actually get called with the 302! It looks like, under the covers, the browser is following the redirect & fetching the login page, and then this gets hit with the jQuery JSON.parse error when it tries to parse the login page HTML as JSON. (And at that point, xhr.status
is 200, because the second HTTP request succeeded!)
Returning a function instead of an object behaves the same, and looks like this:
var editorAjax = function( url ) {
return function ( ignoredMethod, ignoredURL, data, success, error ) {
$.ajax( {
type: 'POST',
url: url,
contentType: 'application/json',
data: JSON.stringify(data),
dataType: 'json',
success: function ( json ) {
success( json );
},
error: function ( xhr, jqAjaxError, thrown ) {
// we don't get xhr.status == 302 in here...
error( xhr, jqAjaxError, thrown );
}
} );
};
};
So, if (IF!) handling the session timeout here is the right thing to do... how do I do it? And if not, how should I handle it?
Answers
Great example
Rather than attempting to do this on a per
$.ajax
call, which is sure to lead to madness, I'd suggest using jQuery's global Ajax event handlers - specifically theajaxError
handler. There you can just dump them back to the login page and call it done for the whole page.ALlan
(Well, the truth is, my production data is all 90's boy bands, but I didn't want people to find out I wasn't metal.)
Ah, thanks!
These aren't exactly working for me--I can see my handlers for
ajaxSuccess()
andajaxComplete()
get hit when the page first loads, but after the session times out, it looks like the 302 redirect is being followed automatically, and the "successful" load of the login page hits the$.ajax({ ... success: function (...) {
on my Editor'sinitCreate
/initEdit
and croaks (in my code, when it hits the unexpected login page HTML) withoutajaxError()
,ajaxSuccess()
, orajaxComplete()
getting called.Still, this seems like a step in the right direction; maybe
jQuery.ajaxTransport()
will let me see when a 302 is received.It looks like XMLHttpRequest will automatically follow redirects (unfortunately in this case). I couldn't find explicit mention of that in the spec, but this section does say:
So I think what you might need to do here is instead of returning 302, return
401 Not Authorized
for this sort of error. Then the client-side can see that 401 and redirect the browser itself.Allan