Hack 8. Handle Request Object Errors


Design your Ajax application to detect any server errors and provide a friendly user message.

Much of the oomph behind Ajax technology is that it allows JavaScript to connect with a server program without the user intervening. However, JavaScript developers often have no control over the server component itself (which could be a web service or other software designed outside their organizations). Even if your application involves your organization's server component, you cannot always be sure that the server is behaving normally or even that your users are online at the moment they trigger your request object. You have to make sure that your application recovers in the event that the backend program is unavailable.

This hack traps errors and displays a meaningful error message, in the event that the Ajax application loses server contact.

Problems, Problems...

This hack addresses the following exceptional events, and recommends ways for the application to recover from them:

  • The web application or server component you are connecting with is temporarily unavailable.

  • The server your application is connecting with is down, or its URL has changed unbeknownst to you.

  • The server component you connect with has one or more bugs, and it crashes during your connection (yeech!).

  • When you call the open( ) method with the request object, your code uses a different host address than the address from which the user downloaded the web page. The request object throws an exception in this case when you try to call its open( ) method.

You can use this hack's exception-handling code in any application. This hack uses the stock calculation code from "Receive Data as a Number" [Hack #6]. We'll take a look at the code that initializes the request object and the exception-handling mechanism in a moment, but first, here's the HTML file that imports the JavaScript code from hack6.js:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"         "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"> <html> <head>     <script type="text/javascript" src="/books/4/254/1/html/2/js/hack6.js"></script>     <meta http-equiv="content-type" content="text/html; charset=utf-8" />     <title>Tally your stocks</title> </head> <body> <h3>Your total Stock Holdings</h3> <form action="javascript:void%200" onsubmit=         "getStockPrice(this.stSymbol.value,this.numShares.value);return false">     <p>Enter stock symbol: <input type="text" name="stSymbol" size="4">             <span ></span></p>     <p>Enter share amount: <input type="text" name="numShares" size="10"></p>     <p><button type="submit">Get Total Value</button></p>     <div ></div> </form> </body> </html>

When users load this file into their browsers, they see the screen shown in Figure 1-11.

Figure 1-11. Request a stock's price


The code we are interested in can trap exceptions involving unavailable applications, backend servers that are down, backend server bugs, and erroneous URLs. The handleResponse( ) function is the event handler for managing the server response, as in request.onreadystatechange=handleResponse. The following code uses a nested try/catch/finally statement to deal with invalid numbers handled by the application, as discussed in "Receive Data as a Number" [Hack #6].

function handleResponse(  ){     var statusMsg="";     try{         if(request.readyState == 4){             if(request.status == 200){                 /* Check if the return value is actually a number.                  If so, multiple by the number                 of shares and display the result */                 var stockPrice = request.responseText;                 try{                     if(isNaN(stockPrice)) { throw new Error(                             "The returned price is an invalid number.");}                     if(isNaN(numberOfShares)) { throw new Error(                             "The share amount is an invalid number.");}                     var info = "Total stock value: $"+                       calcTotal(stockPrice);                     displayMsg(document.                     getElementById("msgDisplay"),info,"black");                     document.getElementById("stPrice").style.fontSize="0.                     9em";                     document.getElementById("stPrice").innerHTML ="price: "+                             stockPrice;                 } catch (err) {                     displayMsg(document.getElementById("msgDisplay"),                             "An error occurred: "+                             err.message,"red");                 }             } else {                 //request.status is 503 if the application isn't available;                  //500 if the application has a bug                 alert(                         "A problem occurred with communicating between the "                         "XMLHttpRequest object and the server program. "+                         "Please try again very soon");             }         }//end outer if     } catch (err) {         alert("It does not appear that the server "+               "is available for this application. Please "+               "try again very soon. \\nError: "+err.message);     } }

Now, let's take a look at how this code handles the different types of exceptions previously enumerated.

Floored Server

A try block traps any exceptions thrown within its curly braces ( {}). If the code throws an exception, this mechanism executes the code within the associated catch block. The inner try block, which is designed to manage exceptions thrown in the event of invalid numeric values, is explained in "Receive Data as a Number" [Hack #6].

So, what happens if the server host is completely down, even though the URL your application uses is otherwise correct? In this case, the code's attempt to access the request.status property throws an exception because the request object never receives the expected response header from the server and the status property is not associated with any data.

As a result, the code displays the alert window defined in the outer catch block. Figure 1-12 depicts what the alert window looks like after this type of error.

Figure 1-12. Uh-oh, server down


The code displays a user message, as well as the more techie error message associated with the exception. You can leave out that part of the message if you desire; it is mainly useful for debugging purposes.

The err variable in the code is a reference to the JavaScript Error object. The message property of this object (as in err.message) is the actual error message, a string generated by the JavaScript engine.


If you do not include this TRy/catch/finally mechanism, the user sees just an alert window containing the indecipherable error message generated by JavaScript. After dismissing this window (or leaving the computer in frustration), the user has no way of knowing what state the application is in.

Backend Application Out to Lunch

Sometimes the application server or host is running okay, but the server component you want to connect with is out of service. In this case, the value of the request.status property is 503 ("Service Unavailable"). Because the status property holds a value other than 200, this hack's code executes the expression contained within the else statement block:

} else {     //request.status is 503 if the application isn't available;      // 500 if the application has a bug     alert(             "A problem occurred with communicating between the "             "XMLHttpRequest object and the server program. "+             "Please try again very soon"); }

In other words, the user sees an alert window explaining the application's status. This alert also appears if the server component has a bug and crashes. This event typically (such as with the Tomcat servlet container) results in a 500 response status code ("Internal Server Error"), so response.status evaluates to 500 instead of 200 ("Okay"). In addition, any 404 response codes involving a static or dynamic component that the server cannot find at the URL you provided are captured with this TRy statement.

The try/catch/finally statement is available only with JavaScript engines of JS Version 1.4 or later. The optional finally statement block follows the catch block. The code enclosed by finally{...} executes regardless of whether or not an exception is thrown.


Whoops, Wrong URL

What if the URL that your Ajax application uses in the request.open( ) method is wrong or has changed? In this case, the request.open( ) call throws the exception, so this is where you have to position your try/catch/finally statement. The code at the top of the next example constructs a request object [Hack #1]. The following function definition, initReq( ), catches the exception just described:

function httpRequest(reqType,url,asynch){     //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");         }     }     //the request could still be null if neither ActiveXObject     //initialization succeeded     if(request){         initReq(reqType,url,asynch);     } 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){     try{         /* Specify the function that will handle the HTTP response */         request.onreadystatechange=handleResponse;         request.open(reqType,url,bool);         request.send(null);     } catch (err) {         alert(                 "The application cannot contact the server at the moment."+                 " Please try again in a few seconds.");     } }

Another variation of this error is when the URL you use with the request.open( ) method includes a different host than the host from which the user downloaded the web page. For example, say the user downloads the web page from http://www.myorg.com/app, but the URL you use for open( ) is http://www.yourorg.com. This type of error is also caught by the code's try/catch/finally statement.

You can also optionally abort or cancel the request in the catch block with request.abort( ). For more information, see "Set a Time Limit for the HTTP Request" [Hack #70] and its discussion of setting a timeout for the request and aborting it in the event that the request is not completed within a certain period.





Ajax Hacks
Ajax Hacks: Tips & Tools for Creating Responsive Web Sites
ISBN: 0596101694
EAN: 2147483647
Year: 2006
Pages: 138

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net