Skip to main content

AJAX Responses Strategies

Posted by jhook on December 3, 2006 at 6:12 PM PST

Part of Avatar for JSF was being able to make a single, lightweight request to the Server and actually receive multiple elements at once in a single HTTP Response. An example would be a single button that would force re-rendering of 5 different parts of the page with one AJAX request. IMHO, this approach is MUCH more efficient that all of these client-side event/observer systems that produce 4 or 5 separate AJAX requests for updates (the network sucks).

Anyways, if we have 5 different things we want to respond back with at once, how do we structure the HTTP response without ruining the original data-- may it be Strings, HTML, XML, or JSON?

We also have the use case of accepting the targeted response data, in addition to any other elements that are to be refreshed. An example would be responding back with some String, but your listeners on the server also want to re-render the cart total and a few other elements on the screen-- not part of the original response.

Response Headers

My first solution was to demarcate the response into separate headers. Each element to be updated had it's own header to occupy, leaving the body of the message alone (see above). This was a perfect or natural way of separating the response up based on HTTP's own spec. The problem is that HTTP containers never intended to carry that much information in their headers, and to prevent buffer attacks, many are capped at a few kb in size. So your refresh of the main table of data would always get chopped off or force an error in the container. Anyways, I think IE also caps the header size acceptable in the response.

So while this solution worked, it has a size cap which is very hard for a framework to enforce.

XML Response

Another idea, which many use, is to break up the response into separate XML nodes in a parent document, allowing CDATA chunks of XML, HTML, or JSON:

<async-response id="5434">
    <encode id="table"><![CDATA[ ... ]]></encode>
    <encode id="cartSpan"><![CDATA[ ... ]]></encode>
    <encode id="footerTotal"><![CDATA[ ... ]]></encode>
    <body><![CDATA[ ... ]]></body>
</async-response>

While we've moved all of the response out of headers and into the body, we've created issues for ourselves around doubling CDATA blocks, which are illegal according to the w3c police. Even if you do the ']]]]>' trick, you will still have problems with some browsers. It's still somewhat tricky.

JSON Response

JSON offers the same capabilities as using XML, being extremely flexible in representing different bits of data, but there's one major problem-- double encoding JSON. If we are trying to create a solution that accomodates all response types, who's to say that one of the responses isn't already JSON, and if we re-encode as JSON, we could end up with unusable garbage in the response.

{
    id:543,
    state:'REALLY+LONG+STRING',
    encode: {
        'table':'....',
        'cartSpan':'....',
        'footerTotal':'....'
    },
    body: '....'
}

VLSN Response

If we choose XML or JSON, it seems we might clobber encoding by either doubling CDATA/entity markup or double escaping JavaScript. So lets try to take those strategies out and just take the simplest approach of producing one Very Long String Notation!

Instead of trying to demarcate within a single body (XML, JSON), we just write everything out in one continuous String, noting when each chunk starts and stops in a separate table. This table can then be stored as a much smaller Response Header or as the first line of the response body.

{id:[0,3],state:[4,4503],encode:{'table':[4504,6004],'cartSpan':[6005,6240],'footerTotal':[6241,6733]},body:[6734,7320]}
340XHHUERe+JeKljfaefe.....

Now you don't have to worry about encoding at all, you just take everything written as is!