A technical post for a change
As you might have guessed, Mibbit relies heavily on XMLHttpRequest. This is a handy javascript mechanism to request data from the originating webserver.
Every time you say something on mibbit, one of these XHR requests fires off to the Mibbit server to tell it what you said. The typing notifies, when you join a new channel, all communications is done via XHR.
Now the XHR uses straight HTTP as its protocol, which is ok, we can try and make the browser use keep-alive so that it’s all done down the same connection. But what about the headers?
Well, when you’re doing a lot of XHR, the headers can become a problem. We can finely tune the headers we send out in the server response, here’s what Mibbit sends back:
Connection: keep-alive
Content-Type: text/plain
Content-Length: 67
That’s it. We don’t need anything else. Note that the text/plain is needed for some browsers which assume xml and then start throwing hissy fits when it doesn’t parse as an xml document.
But what about the headers the browser sends?
The size of headers in a basic XHR request:
Firefox3: 495 bytes
IE7: 289 bytes
Safari: 357 bytes
That means if your little ajax request is simply sending 5 bytes, you’re still going to send a few hundred bytes. Wasting time, bandwidth, and processing. For XHR requests, you often simply do not need half of those headers. I already know what the user-agent is, and can send it at the start of the comms if needed. I don’t need an Accept header, because it’s irrelevant. The XHR is going to send back text. etc
We can do a little bit better… Here are the numbers when we add a few lines of js to cut down headers.
Firefox 3: 268 bytes
IE7: 259 bytes
Safari: 322 bytes
The code:
setHeaders = function(xhr) {
function safeSet(k, v) {
try {
xhr.setRequestHeader(k, v);
} catch(e) {}
}
safeSet("User-Agent", null);
safeSet("Accept", null);
safeSet("Accept-Language", null);
safeSet("Content-Type", "M");
safeSet("Connection", "keep-alive");
safeSet("Keep-Alive", null);
}
All the code does is try as hard as it can to remove headers, or set them to small values. So instead of firefox 3 sending its massive user-agent string to your server *every* *single* *time*, it doesn’t send it at all
There may be other headers that you can remove, if there are extra headers sent. I’m sure the code above can also be improved to take account of different browsers.
Also note that the mileage really does vary from browser to browser. The code above actually increases the headers in opera, as it appends the values. eg User-Agent = null, Opera……
The lack of some headers may affect web proxies possibly – that should be tested. It would be possible to detect such a case at runtime and leave the header in though.
The w3 spec regarding this can be found here http://www.w3.org/TR/XMLHttpRequest/
Mibbit handles an average of about 600 XHR requests a second. That means if everyone is using firefox3, the saving would be 136kbytes/second – That’s 339GB per month!
All in all, this will reduce bandwidth usage for Mibbit and make things just that bit better
No related posts.
heh, that’s interesting AJAX-Hackery
Thanks for sharing that! Quite interesting, and makes you start wondering where else one can improve efficencies.
The question is, why not use comet instead?
est: Umm… This is comet.
Excellent post, very interesting and useful, will implement it’s wisdom on my next ajax app
(found the post via reddit btw, look forward to exploring your blog based on this post!)
Very interesting post – those who try to specify XMLHttpRequest have been discussing how to deal with the value “null” in this context. You’ve presented quite a strong argument for using null to remove headers that would otherwise be sent. (Likely some headers should be sent anyway because of security implications – e.g. content-length – but by your bandwidth calculations there is a strong use case for allowing removal of the others. Especially if some browsers already support it.)
Have you done any tests with Google Chrome? I know it was advertised as being a browser designed to better handle JavaScript applications. When using Mibbit, I tend to use Chrome. I’m curious how it ranks up when compared to other browsers that use Mibbit.
We’re investigating implementing this technique in the javascript client for Meteor, a comet server. Question: Have you come across any way of suppressing the Cookie header from XMLHTTPRequests? This is generally responsible for the majority of request weight, and sometimes there’s not much you can do about it (if you’re operating a subdomain of a major news site, for example, where the admins of the core site see fit to drop billions of cookies)
Andrew, solve it at the source. Don’t send the cookies.