What's Portable
The good news is that most of the logic required for
synchronous requests is highly portable. Once you have an XMLHttpRequest object variable, code such as this works well across all modern browsers.
// the request variable holds an XMLHttpRequest
// object instance
request.setRequestHeader("X-Foo-Header","Bar");
request.open("GET", "post_handler.cgi");
request.send("");
if ( request.status == 200 )
{
len = request.getResponseHeader("Content-Length");
len = request.getAllResponseHeaders().length;
alert(request.status);
alert(request.responseText);
alert(request.responseXML);
}
This code manipulates HTTP headers both before and after the request runs. It can also inspect the data sent back using portable object properties such as
status. For simple cases, that may be all you need. For more complex cases (which includes early versions of Opera), you need a
scripting library from Andrew Gregory to put these features in place before you can assume support for all version 5.x onwards browsers. Those old Opera versions won't be around for long, though.
What's Not Portable
Alas, there's a bit of custom coding to do both before and after using the XMLHttpRequest object.
First, creating the request object differs depending on the browser version. As Microsoft's implementation is an ActiveX control, as compared to the JavaScript implementations of the later imitators, you must treat IE differently. Here's some portable code that instantiates an XMLHttpRequest object based on the browser type and version.
var ua = navigator.userAgent.toLowerCase();
if (!window.ActiveXObject)
request = new XMLHttpRequest();
else if (ua.indexOf('msie 5') == -1)
request = new ActiveXObject("Msxml2.XMLHTTP");
else
request = new ActiveXObject("Microsoft.XMLHTTP");
The preceding code shows that for all browsers except IE, you can use the Mozilla semantics. For IE, the script grabs the
userAgent string and determines the IE browser version based on the version number contained in that string. For IE versions other than 5x, it uses the most up-to-date ActiveX implementation of
XMLHttpRequest. For ancient 5.x versions it creates an older ActiveX implementation instance. Both ActiveX objects are marked as "script safe" and "web safe," so users don't need to lower their security settings for you to use these objects.
Second, asynchronous requests need a bit of portability legwork. The process to install a handler is different for IE and Mozilla.
If you try to use Mozilla's
onload object property to register the handler for all browsers (as shown earlier in this article) then you're in for trouble. That approach allows your handler function to be very simple, but it's not portable. Here's a portable handler registration that has the same effect as an
onload handler target, but uses the portable
onreadystatechange event instead.
function progress_handler()
{
if (request.readyState != 4 ) // not yet finished
return;
// finished. Continue as before
if (request.status == 200 )
{ … }
}
request.onreadystatehandler = progress_handler;
request.send(…);
The Google "Suggest" Code Squeeze
One popular user of
XMLHttpRequest is the
Google Suggest Web page. This page is the same as the standard search window, but adds a drop-down list of remembered terms to the text box. It's like the drop-down list in the location bar of the browser, except the list of terms comes from Google's own server. The page retrieves the terms from the server after you've displayed the page by repeatedly submitting your typed partial search terms to the Google server in real time.
If you view the source of Google's page, you'll find a
<script> tag that includes a file called
ac.js. Load that rather cryptic file and you'll see buried in it a very short cross-platform wrapper for the XMLHttpRequest object. Although you'll have to decode the meaningless variable names, this is a good example on which to base your cross-platform JavaScript XMLHttpRequest wrapper code.
So, the next time you begin planning a Web application, ask yourself if you're building a book or a console-type application. If the latter, replacing the current page needlessly can be like flashing a sign in the user's face. Take a step back and ask yourself: Is refreshing the entire page really necessary? If not, the
XMLHttpRequest object is an increasingly viable alternative for sophisticated browser-based applicationsand now that you know the required cross-platform scripting contortions aren't that painful, if you experiment with this useful object you may find that you're hooked for good!