Dojo xhr response code handling patch

While working on a project using Dojo to create a single page app, I came across the issue of how to handle server side session timeouts. There are many ways to deal with the first login or an authentication timeout, for example you can use a timer on the frontend or periodically ask the server or just reload the app, if your server replies with a 401 response code. Your server code does reply with meaningful http status codes, doesn’t it?

I did not like the solutions recommended to me. As logging in into your application should not be an “error state” but a normal use case, any solution disrupting the usage flow was out of the question. Essentially, I looked for a way to pause the current server call, and basically the application itself, to handle the authorization. Afterwards everything should resume as if nothing has happened and the failed server call should be repeated, this time with a valid session.

There are several ways to implement this. You could for example write a proxy function for every ajax call to encapsulate and automate this logic. But if you want to rely on Dojo’s existing ways to aquire data from the server this would not work, as you cannot supply your own xhr instance.

I decided on monkey patching (or duck punching, as some people call it) Dojo’s xhr function to transparently and globally handle different response codes. The result is a small (130 LOCs uncompressed and heavily documented) function which proxies the original xhr function and adds the response code handling logic. You can either block any other ajax call if you receive a non-fatal response, or let everything else fail and just deal globally with the system error.

Grab the js file from Github and include it after dojo.js and before your application code:

<script src="js/dojo/dojo.js" type="text/javascript" charset="utf-8"
djConfig="..."></script>
<script src="js/dojoXhrExtension.js"></script>
<script src="js/yourappcode.js"></script>

HTML

Before making any xhr calls or initializing any Dijit components which could do that, define your handler functions this way:

dojo._handleXhrStatus[401] = {
retryAfterwards: true,
handler: function() {
var d = new dojo.Deferred()
 
// your authorization code, for example:
dojo._xhr("GET", {
url: "auth/signIn",
content: {
username: "administrator",
password: "god"
}
}).then(function(result) {
d.resolve()
}, function() {
d.reject()
})
 
return d
}
}

JavaScript

If any xhr call gets a 401 response, your configured function is invoked. While you handle the event, any other ajax call is paused until you resolve/reject the Deferred.

You can handle 401s, but also any 5xx for example. If you cannot resume normal operations afterwards, set retryAfterwards to false to inhibit the ajax call blocking.

I haven’t found any other “official” way to accomplish this. So if you have any comments, recommendations or have found any bugs, please do not hesitate to drop me an email.

Update 12/27/2011

I updated the patch to use the handle() callback of the xhr function. This way, we can get ioargs information irrespective from the response code.

The ioargs information is also now additionally stored in the Deferred returned to the caller. This fixes some problems with some Dojo datastores, like the dojox.data.JsonRestStore. Thanks to Johannes Kanefendt for this bug report.

blog comments powered by Disqus
More posts can be found in the blog archive.