
The Problem
You gotta love Microsoft! Sometimes I think they've taken liberties with their browsers that are designed just to be annoyances for the programming community at large. Case in point, we recently inherited a Formidable Pro project that uses a jQuery.ajax() call to retrieve a confirmation number from a database on a remote server when a user clicks on the form's submit button (See here). The remote server runs Windows and Internet Information Server (IIS). After refactoring the code to improve performance and overcome a timing issue, it all appeared to be working perfectly in all browsers, except that is…, (yes, you guessed it!), Internet Explorer. Now to only figure out why.
The Analysis
The jQuery.ajax() request as originally written looked like this:
The content is a well-formed XML record built with the values from the Formidable Pro form. Since we inherited this project, this code had already been built. We assumed that it was written to satisfy the specification provided by the customer. We did not have access to the original specifications to verify the work.
Rule Out Cross-Site Scripting
The path to the remote server is a subdomain of the primary domain. To help with the troubleshooting, we added a field to the Formidable Pro form and created a function to write to it as an error log. One of the errors recorded in a failed submission has a jqXHR status code of 0. Status code 0 is generally triggered when there is an attempt at cross site scripting and access is denied, or the connection is refused at the server. With this setup it could be one or both of these issues. We decided to rule out cross-site scripting first.
With cross-site scripting, subdomains are considered different than the primary domain and will fail the Same Origin Policy unless both domains declare the same document.domain DOM property (and even then, different browsers behave differently). The fact is that we are sending a request from a primary domain to a subdomain. To our eyes, this shouldn’t be a problem, but this is a problem for some browsers. Maybe it's a problem for IE? It certainly wasn't an issue for Firefox, Chrome, or Safari during our testing. The link to the Same Origin Policy provides some remedies for relaxing the cross site scripting issues. Adjusting the jQuery.ajax() request is as simple as adding "crossDomain: true" to the function's parameters. Again, this worked with every browser except IE. Cross-site scripting is eliminated as the cause for the IE failure.
HTTP GET vs. HTTP POST
When we tested with IE, as soon as the function was invoked we could see in the Network tab of the browser's development tools that the browser cancelled the request. It would not send the request to the server. Why would the browser cancel the request?
As it turns out, this was due to a long ago forgotten fact about Internet Explorer. IE is designed to restrict URLs to a length of 2083 characters. The records produced by the form easily exceed that length. If a URL is longer than the restricted length, IE will not process the request.
Ajax data can be sent over the Internet either through a HTTP GET or HTTP POST request. POST requests supply additional data from the client (browser) to the server in the message body. In contrast, GET requests include all required data in the URL. Ajax requests can use either method by specifying the type of the request as either "POST" or "GET" (default) in the Ajax function. The method specified determines how the data is submitted to the server. When the method is GET, all data is encoded into the URL, appended to the action URL as query string parameters. Remember query strings? Because of the GET, this request was being formed as //path-to-remote-server/?action=ajax-action¶m1=param-value1¶m2=param-value2¶m3=param-value3, etc.. GET requests can create very long URLs. With POST, the data appears within the message body of the HTTP request, which effectively overcomes IE’s URL length limitation. Changing the Ajax request type to POST solved this problem.
Content Type
Changing the request type to POST introduced yet another problem. This time, viewing the Network request/response cycle in the browser's development tools, we could see that IE was sending the request, but the server was responding with a HTTP 500 internal server error.
POST request require a content type of "application/x-www-form-urlencoded; charset=UTF-8" (jQuery.ajax() default) regardless of the actual type of data being sent. The jQuery.ajax() request was sending data in XML format with its content type set to text/xml. IIS didn't like this. The solution was to remove contentType: "text/xml" from the request function so jQuery.ajax() used its default.
Encoding Special Characters
One last issue remained. IIS immediately rejected any Ajax request where one of the XML values included a special character. For example, if the value of a business name field was "Sanford & Sons, Inc.", the request choked because of the ampersand. Special characters need to be converted to HTML entities when sent through Ajax requests. Neither jQuery nor JavaScript have a direct function for converting special characters to HTML entities. The following quick 3-line function solves this issue.
This function works by creating a div in memory. The div does not exist on the page. The function assigns the passed parameter to the div's inner text, then returns the encoded content. To use this you simply pass the form's field value as the parameter.
Conversely, you can decode HTML entities into special character by reversing the text() and html() functions.
The Resolution
After all is said and done, here is the final code for the jQuery.ajax() call:
Nice article Mr Victor, it’s very helpful
I promise, I wanna share your article to my friends.
Thank You.
Thank you Azmi.