Previous Page
Next Page

Hack 3. Use Your Own Library for XMLHttpRequest

Break out the code that initializes the request object and sends requests to its own JavaScript file.

To cleanly separate the concerns of big Ajax applications, create a separate file that manages the XMLHttpRequest object, then import that file into every web page that needs it. At the very least, this ensures that any necessary changes regarding how the code sets up the request object have to be made only in this file, as opposed to every JavaScript file that uses Ajax-style requests.

This hack stores all the request objectrelated code in a file called http_request.js. Any web page that uses XMLHttpRequest can then import this file in the following way:

<script type="text/javascript" src="js/http_request.js"></script>

Here's the code for the file, including all the comments:

var request = null;
/* Wrapper function for constructing a request object.
 Parameters:
  reqType: The HTTP request type, such as GET or POST.
  url: The URL of the server program.
  asynch: Whether to send the request asynchronously or not.
  respHandle: The name of the function that will handle the response.
  Any fifth parameters, represented as arguments[4], are the data a
  POST request is designed to send. */
function httpRequest(reqType,url,asynch,respHandle){
    //Mozilla-based browsers
    if(window.XMLHttpRequest){
        request = new XMLHttpRequest(  );
    } else if (window.ActiveXObject){
        request=new ActiveXObject("Msxml2.XMLHTTP");
        if (! request){
            request=new ActiveXObject("Microsoft.XMLHTTP");
        }
    }
    //very unlikely, but we test for a null request
    //if neither ActiveXObject was initialized
    if(request) {
        //if the reqType parameter is POST, then the
        //5th argument to the function is the POSTed data
        if(reqType.toLowerCase(  ) != "post") {
            initReq(reqType,url,asynch,respHandle);
        }  else {
            //the POSTed data
            var args = arguments[4];
            if(args != null && args.length > 0){
                initReq(reqType,url,asynch,respHandle,args);
            }
        }
    } else {
        alert("Your browser does not permit the use of all "+
              "of this application's features!");
    }
}
/* Initialize a request object that is already constructed */
function initReq(reqType,url,bool,respHandle){
    try{
        /* Specify the function that will handle the HTTP response */
        request.onreadystatechange=respHandle;
        request.open(reqType,url,bool);
        //if the reqType parameter is POST, then the
        //5th argument to the function is the POSTed data
        if(reqType.toLowerCase(  ) == "post") {
            request.setRequestHeader("Content-Type",
                    "application/x-www-form-urlencoded; charset=UTF-8");
            request.send(arguments[4]);
        }  else {
            request.send(null);
        }

    } catch (errv) {
        alert(
        "The application cannot contact "+
        "the server at the moment. "+
        "Please try again in a few seconds.\\n"+
        "Error detail: "+errv.message);
    }
}

The applications that use this code call the httpRequest( ) function with four or five (with POST requests) parameters. You see lots of examples of calling this function in the other hacks. Here's another:

var _url = "http://www.parkerriver.com/s/sender";
var _data="first=Bruce&last=Perry&middle=W";
httpRequest("POST",_url,true,handleResponse,_data);

The code comments describe the meaning of each of these parameters. The last parameter represents the data that accompanies a POST request.

A POST HTTP request includes the POSTed data beneath the request-header information. A GET request, on the other hand, appends parameter names/values onto the URL.


If the code is not using POST, the client code uses only the first four parameters. The fourth parameter can be either the name of a function that is declared in the client code (i.e., a response-handling function that appears outside of the http_request.js file) or a function literal. The latter option involves defining a function inside a function call, which is often awkward and difficult to read. However, it is sensible in situations in which the HTTP response handling is short and simple, as in:

var _url = "http://www.parkerriver.com/s/sender";
//a debugging setup
httpRequest("POST",_url,true,function(  ){alert(request.responseText);});

httpRequest( ) initiates the same browser detection and setup of XMLHttpRequest for Internet Explorer and non-Microsoft browsers as described in "Detect Browser Compatibility with the Request Object" [Hack #1]. initReq( ) handles the second step of setting up the request object: specifying the onreadystatechange event handler and calling the open( ) and send( ) methods to make an HTTP request. The code traps any errors or exceptions thrown by these request method calls using a try/catch statement. For example, if the code calls open( ) with a URL specifying a different host than that used to download the enclosing web page, the try/catch statement catches the error and pops up an alert window.

Finally, as long as the web page imports http_request.js, the request variable is available to code external to the imported file; request is, in effect, a global variable.

request is thus reserved as a variable name because local variables that use the var keyword will supercede (with unintentional consequences) the globally used request, as in the following example:

function handleResponse(  ){
//supercedes the imported request variable
var request = null;
try{
if(request.readyState == 4){
if(request.status == 200){...



Previous Page
Next Page