Tuesday, March 29, 2005

Make your Apache HTTP errors more Ajax-friendly

Applications that use remote scripting or Ajax-style communications can have problems when things go wrong at the server end. How does one detect a 404 or 500 error inside your hidden IFRAME, and how can an application be designed to handle such an error?

A client-side developer would probably suggest walking the DOM tree out to the IFRAME document and looking for the status text. But why not make it easier by having the server hand back HTTP errors to your application as JavaScript? This can be done with relative ease with Apache (I'm sure other servers can be configured similarly) with three basic steps:

  1. Create a custom error page
  2. Include JavaScript in the error page that interacts with the application (via the containing frame or IFRAME)
  3. Use Apache's ErrorDocument directive to tell the server to deliver the custom error page when an error occurs

Below is a sample error page written in PHP. Apache provides the basic variables needed to determine the status; here, we just pluck them from PHP's global variables and plug them into a JavaScript block. Once loaded, the JavaScript looks for an onServerError handler in the parent window (assuming the page request is made from a frame or IFRAME) and invokes it with the HTTP status information.

<?
  /* error.php */
  /* this line ensures the client gets the HTTP status */
  header("Status:" . $REDIRECT_STATUS);
?>
<!-- include DOCTYPE of choice here -->
<html>
<head>
  <title>Error <? print $REDIRECT_STATUS; ?></title>
  <script>
    var win = (window.parent) ? window.parent : window;
    if (win.onServerError) {
      win.onServerError(
        {
          status:'<? print $REDIRECT_STATUS; ?>',
          url:   '<? print $REDIRECT_URL; ?>',
        }
      );
    }
  </script>
</head>
<body>
  <h1>Error <? print $REDIRECT_STATUS; ?></h1>
  <p>
     This page should have invoked a 
     JavaScript onServerError handler 
     if one was provided.
  </p>
</body>
</html>

We'll save this file as error.php and place it in a directory named /rs-errors/. Next, we have to tell Apache to use our error page for selected HTTP error statuses. We can do this by adding ErrorDocument directives to an .htaccess file placed inside the directory at which our remote scripting requests are targeted. For example, if you're sending requests to http://appserver.example.com/api you'll want to put these in the .htaccess file for that directory:

ErrorDocument 404 /rs-errors/error.php
ErrorDocument 500 /rs-errors/error.php

Now, if a 404 or 500 error occurs inside of /api Apache will use our error.php as the error document served to the browser.

It should be relatively simple to implement this in a JavaScript application now:

<script>
  function onServerError(e) {
    switch (e.status) {
      case '500':
        // handle a 500 error here
        break;
      case '404':
        // handle a 404 error here
        break;
    }
  }
</script>

...

<iframe src="http://appserver.example.com/api/some-bogus-request-here">
</iframe>

When the IFRAME attempts to load the bogus URI, Apache will throw a 404 error and invoke error.php. The JavaScript in the head of our error page will attempt the onServerError handler defined in the application. The application can now decide how to best communicate the error state to the user without appearing broken.

Caveat: don't forget that IE will attempt to serve up its own custom 500 page from the local machine, so it might be a good idea to pad your error page with 512K 512 bytes (or more) of whitespace or commented text to convince IE that your error is the one to show.

If you prefer an "Ajax (The X Is For 'XML' Dammit!)" approach, you can easily write your custom error page to deliver HTTP statuses as an XML payload instead of JavaScript. I prefer JavaScript myself since I don't have to parse it, but XML might be preferred if you're sharing data across different apps on different platforms.

Reference:

14 Comments:

At 3:12 AM, Anonymous Anonymous said...

According to the Microsoft article you linked to, you need 512 _bytes_ of padding, not 512K of padding as stated in your post.
(Which is fortunate, really.)

 
At 5:45 AM, Anonymous Anonymous said...

Surely the client JavaScript code should already be handling the XMLHttpRequest status codes (using the status property) when the request is received? The mechanism you propose sounds a bit cumbersome to me.

 
At 8:14 AM, Blogger scottandrew said...

canis: oops, fixed, thanks :)

anon: the Ajax appreach doesn't necessarily mean the client app is using XMLHttpRequest. The sample code above assumes you're using a frame or an IFRAME for client-server transport, without XMLHttpRequest.

 
At 1:38 PM, Blogger Roberto Iza Valdés said...

This comment has been removed by a blog administrator.

 
At 2:58 PM, Blogger Roberto Iza Valdés said...

This comment has been removed by a blog administrator.

 
At 2:03 PM, Blogger Roberto Iza Valdés said...

This comment has been removed by a blog administrator.

 
At 7:57 PM, Blogger Tony said...

Nice Apache info. I myself have worked with apache enough to know any tip I can get it well worth it.

Come visit my article submission directory sometime, great info there, and I always love people submitting more.

 
At 5:40 AM, Blogger HiiFii Webservices said...

I liked you Blog so much,so i also wanted to show you some good resourses on the net.
Learn to earn 90000$/Month
For which you may also see my Personal Website
Here.
and for a Personal Education Career Tools
free Study Database.
This site is for seeing the
Hifi Electronics.
And this is for
World Class Gadgets

 
At 4:35 PM, Blogger Roberto Iza Valdés said...

This comment has been removed by a blog administrator.

 
At 4:37 PM, Blogger Roberto Iza Valdés said...

This comment has been removed by a blog administrator.

 
At 12:17 AM, Blogger HiiFii Webservices said...

Please See these new Sites purchased by me.
Sluze
Adsense Talk
DomainBar
HostBoard
Review my Site

Please Check out my new Free Softwares WebsiteAll Free Softwares

please check my latest Blog on Increasing memory Memory Gain

 
At 8:17 AM, Blogger Roberto Iza Valdés said...

This comment has been removed by a blog administrator.

 
At 9:12 AM, Blogger Unknown said...

This comment has been removed by the author.

 
At 11:15 PM, Blogger Unknown said...

This comment has been removed by the author.

 

Post a Comment

<< Home