Internet Explorer (and Microsoft Edge) is widely joked about as the bane of any web application developer's existence. This is only somewhat true these days as Microsoft contains to make improvements to their browsers and bring them towards web standards compliance (Edge in particular has come a long way to support HTML5 features); but for those of us that have to support old versions of IE it is as true as it is today as it was nearly 10 years ago. This blog post will hopefully save some poor soul like me that encountered what I consider unexpected behavior and how to workaround it.
IE "Friendly" Error Pages
Internet Explorer undertakes a noble endeavor to provide a smooth and informative user experience for web users who find themselves encountering an error page from a web server. In particular, if a web server responds with a terse message for certain HTTP error codes (400, 403, 404, 405, 406, 408, 409, 410, 500, 501, 505), the resulting server response page will be replaced with a more visually appealing page as well as a more informative page. You've probably seen one of these pages before.
So this means that if you are developing the server side and set a response code of 404
and return a simple HTML page, the user will never see it; instead they will see IE's version.
<html> <head> <title>Not found</title> </head> <body> Page not found </body> </html>
In general, I think this is great. I am a big supporter of giving the user an appropriate error message so they can better understand what happened. If you created this as 404
response, I'd argue with you over a beer that you really should make your error pages fit the aesthetic of your web application and give your users a better idea of what happened. So why, then, am I writing this blog post? Well it goes back to those old days when developers cursed IE...
AJAX File Uploads
We maintain and develop a web application for a client in the healthcare space that needs to accept form data and files from end users. Being healthcare, some of the potential users of the system are at hospitals with monolithic IT departments and architectures that can make upgrading the installed web browser on client computers a difficult (and timely) proposition. Our user base is improving, and hopefully the days of us having to support a client on IE9 are limited, we are stuck there for now.
Of course, IE9 knows nothing of FormData
or the enhanced file operations of HTML5. If you want to upload a file in IE9 and keep the user on the same page, you have to resort to the good ole' hidden iframe
trick. Google it if you are not familiar with the topic because you are lucky enough to have never had to use it, but essentially: (1) you create a hidden iframe
in your DOM and point it to your appropriate server route then (2) POST the form when the user has selected the file to upload (or pressed an appropriate upload button). This has the effect of uploading the file in the iframe
and keeping the user on the original page &mdash a poor mans AJAX upload.
We used this approach to send files with one important additional point, we cared about the response from the server after the file was upload. We wanted to react to potential error cases and alert the user of what happened. Doing this is also somewhat of a hack: the server route needs to respond with a full HTML page and the client then parses the iframe
response and acts accordingly.
Impending Doom...
You might see where this is headed already. We designed a protocol that would: (1) utilize the iframe
to send the file, (2) set the HTTP response to an appropriate error code 4XX
or 5XX
, (3) build an HTML page to respond to error conditions with JSON objects encoded, (4) parse the response on the client side and eval
the response (I know, big no-no, but we already own a mansion in The Land of Hacks) and (5) update the client UI to show the error.
For example, when a user uploaded an image that had already been uploaded, we set the HTTP response to 400
and send the following response to the client-side iframe
<html><head></head><body><div id="response">{"error" : "This file has already been uploaded"}</div></body></html>
In the client, our javascript source would grab the JSON object in the div
element. And thus our ugly IE issue peeks it's head out from around the corner...
For our IE users, we would notice intermittent support requests that they would "upload the file, but nothing would happen". In the case of a successful upload, the file name is added to a list in the client-side HTML and in the case of an error the returned error message should have been displayed on the page in a nice looking error message. The use-case did not occur very often and affected a small percentage of users, but it was a show stopper for them.
Finding the Problem
Debugging this problem was a nightmare; the server was receiving the POST
from the iframe
and building the proper error HTML response. The client, however, was simply throwing a script error in IE because the javascript on the client could not find the response
div and parse the message. The network request looked good but this mysterious HTML started popping up in the iframe
; the HTML was indeed describing an error, but it was not my HTML!
I had no idea even what to Google or how to describe the problem appropriately. After many hours, I happened to come across the following blog post. There it was, clearly spelled out:
For a certain set of HTTP response codes, if the server does not respond with a message size that is greater than a set threshold, Internet Explorer will replace that response with a "friendly" error page.
So it turns out that our very minimal message passing protocol was being replaced because the response was simply too small (in our case, less than 512 bytes).
The Workaround
The "friendly" error pages can be disabled on the client side so that the intended response from the server is displayed. Obviously, we cannot ask all IE users to disable the "friendly" error pages so our web app functions correctly. More so, I think the "friendly" pages are a nice feature it is just that in our non-standard use case, it was breaking our code.
Our solution is instead controlled on the server-side: when responding in an error state from our server routes, we ensure that our response is at least 512 bytes.
resp.setStatus(400); resp.setContentType("text/html"); resp.getWriter().println("" + msg.toString() + "" + StringUtils.repeat("A", 512) + ""); return ;
This would be a pretty ugly error page is displayed on the client, but for our purposes (loaded in the iframe
and parsed with javascript) it gets the job done!
TLDR;
If your server route is responding with an error page that is mysteriously being replaced in Internet Explorer or Microsoft Edge, check those "friendly" error pages!
Also, if I happen to ever meet Eric Lawrence I am buying him a beer!