20

To the point: how would you handle a server-side HTTP 4nn/5nn errors in jQuery's ajax requests? This case concerns a JSP/Servlet webapplication at the server side. Here I am not talking about trivial runtime exceptions such as NullPointerException and so on. Assume that they're all handled perfectly. A good example of such a HTTP 4nn/5nn error is 401 unauthorized (insufficient user rights) and 500 internal server error (database down, I/O error, Errors, etc). Assume that they cannot (or should not) be caught at coding level.

Right now I have just declared an <error-page> in web.xml for those kind of errors. It basically forwards the request to a predefinied JSP/HTML error page wherein the enduser is informed that a serious error has occurred and that the user can contact xx@xx.xx for further assistance. The same page also displays the global details about the error/exception.

It works perfectly in regular HTTP requests, but how would you handle it in XMLHtttp requests using jQuery? What's the best for the user experience? To me, it would be just displaying the entire error page as if it is a normal HTTP request. I've solved it as follows:

function init() {
    $.ajaxSetup({
        error: handleXhrError
    });
}

function handleXhrError(xhr) {
    document.open();
    document.write(xhr.responseText);
    document.close();
}

Although it works perfectly, it feels to me like a hack. Replacing the entire document with the contents of the HTTP error page. But is that also the way you would follow? If not, can you maybe elaborate why not and what way you'd prefer? The only alternative I see is using JS to display some alert/message box to inform the user about the unresolveable error, but the user could dismiss it and continue with the page while that should not be possible.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • if you use a custom modal instead of Alert, such as jqModal or simpleModal, you can make it so that the user is not able to dismiss/close it. You could add your own button to return the user to the homepage, or to a contact page, or whatever other page you'd like, if the error is unrecoverable. If the error _is_ recoverable (you mention the database being down, perhaps a reboot) then a nice Please wait and try again later message might be sufficient (allow the user to dismiss the dialog and try again). – Funka Dec 14 '09 at 21:28

5 Answers5

5

After all, dealing with errors on asynchronous requests the same way as with synchronous requests is the best for user experience. Only, the

function handleXhrError(xhr) {
    document.open();
    document.write(xhr.responseText);
    document.close();
}

will fail in IE6/7/8 when you've <script> elements which needs to be loaded and initialized as well. IE6/7/8 namely won't do that. In order to get IE to do that, you basically need to keep the current <head> element and only replace its children by $("head").html(newHead). The same should be done for the <body> element.

function handleXhrError(xhr) {
    var newDocument = xhr.responseText;
    $("head").html(newDocument.substring(newDocument.indexOf("<head>") + 6, newDocument.indexOf("</head>")));
    $("body").html(newDocument.substring(newDocument.indexOf("<body>") + 6, newDocument.indexOf("</body>")));
}

Nasty, but it's not possible to do a $(xhr.responseText) when the response text represents a whole HTML document with a head and body. Don't forget to alter the substring index accordingly when you've some attributes on <body> of the error page template (e.g. ID, class, etc).

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • It might feel ugly and not AJAX-y, but to have a consistent handling of any exceptional behaviour, this is the only sane way to handle ajax and direct server requests consistently. – matthieus Aug 09 '13 at 11:33
3

Use a JQuery dialog, something like this:

function handleXhrError(xhr) {
   ele = $("<div></div>").appendTo("body");
   ele.html(xhr.responseText);
   $(ele).dialog();

}

I should answer the rest of what you asked. I throw and catch specific exceptions where I can, and send special messages to the client. Sometimes I instruct the client to run a function which may redirect the browser or partially refresh part of the page. It just depends on the circumstances. Catching 400/500 will deal with real errors, but you want to also write JS code once to filter all your AJAX requests for custom error flags that you will return from the server, take a look at this page for more: http://www.bennadel.com/blog/1392-Handling-AJAX-Errors-With-jQuery.htm

Josh Pearce
  • 3,399
  • 1
  • 23
  • 24
  • The `responseText` is in this case a worthfully HTML page, with a head and a body, I am not sure if I would prefer putting it in a dialog div above just replacing the document. As to the blog link, sorry, that didn't add any value to me. – BalusC Nov 16 '09 at 02:18
  • I forgot about the fact it's a whole html page. I actually use an iframe in the dialog, so the injected HTML's style doesn't interfere with mine. As for the link, I was just suggesting that you handle the return function calls for AJAX calls at a low level in your application. – Josh Pearce Nov 16 '09 at 13:20
2

If necessary, you should also be able to re-direct to one of the pre-defined error pages you set-up with window.location.href = "url-to-error-page";

dan_nl
  • 4,456
  • 1
  • 15
  • 7
  • 1
    That would fire a new HTTP request and I'd like not to store the details about the error/exception in the session scope. – BalusC Nov 16 '09 at 01:53
  • Which global details about the error/exception would you want to have show-up? I was thinking that a status of 401 would re-direct to an actual 401 page that sent the 401 header along with it and the same for a 500 ... – dan_nl Nov 16 '09 at 03:54
1

I think it's better to give a short message instead completely rewriting your page. That way it won't interfere much with the page itself. Google Reader and Gmail do something like this. Reader shows the message and doesn't mark your items read, but you can still read all the loaded posts.

Peter Stuifzand
  • 5,084
  • 1
  • 23
  • 28
1

You seem to want to retain a working page/application after you receive an error condition that would result in an unusable state.

I would implement a state history on the client side and revert the page to the last usable state, informing the user via a prominent in-page element what has happened.

The theory behind this is related to transactions. Typically the execution flow is:

  1. Instruct transaction manager to start a transaction
    1. Begin transaction
    2. Capture state
    3. Return control to calling code
  2. Begin operations that are part of transaction
  3. On error: instruct transaction manager to roll back transaction
    1. Return execution environment to state captured above
    2. Discard any data no longer needed (e.g. state serialization)
  4. On success: instruct transaction manager to commmit transaction
    1. Finalize operations in transaction as needed
    2. Discard any data no longer needed

I have not done serious study into transaction management in javascript. Since you state that the server-side error makes the client side unusable, perhaps there is some way to implement portions of the transaction on the server-side. It is important that you not leave things half done there more so than on the client-side.

Have you thought about doing a "pre flight check" request to try to capture these issues before the client-side application attempts to do the real work?

J5.
  • 356
  • 4
  • 10
  • No, not really. I was just trying to share experience with others what would be the best practice for **unrecoverable** errors in case of ajax requests *and* that the returned error is a complete HTML page. I've googled around for long, but I've never seen the `document.open()`, `write(html)`, `close()` approach around, so I was a bit poking around here. – BalusC Dec 13 '09 at 14:18
  • I see. I thought that the question included what the best user experience would be (whether to show a complete error page or allow someone to continue). If you want to keep the user on your site, the best experience is to let them continue with what they are doing and give some feedback about avoiding the error if at all possible. Returning an error page is going to result in refreshes (frustrating the user if that does not result in a usable state with their search results still there, etc) and page abandonments... consider form pre-validation on client side as an example use case. – J5. Jan 08 '10 at 03:02