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:
- Create a custom error page
- Include JavaScript in the error page that interacts with the application (via the containing frame or IFRAME)
- 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.