Saturday, December 4, 2010

CakePHP JSON Response Data in Headers

I recently utilized CakePHP's ability to automatically adjust view parameters based on the requested extension in the URI. This makes it really easy to specify a JSON formatted response by just tacking ".json" to the end of the URI. When I discovered this handy little feature of Cake's, I was praising the framework for such a quick and useful feature. Until things went wrong, of course.

I do most of my development in Chromium, but noticed when I was testing my code for the new JSON responses, data wasn't showing up properly in Firefox. I didn't think much of it and figured I would return to the issue once I could focus on browser compatibility. I eventually, however, found myself at that point in development. I discovered that returning only a sliver of the normal response data lead Firefox to respond properly. I also found Chromium was hitting it's own, significantly higher, limit. Firefox was capping the JSON response at 4096 bytes, whereas Chromium was somewhere in the area of 305kB. The Chromium limit was practically reasonable for my application, but there was no way I could dodge Firefox's measly 4kB cap. But wait, there's no way Firefox limits all AJAX responses to 4kB, right? Gmail can't possibly operate on an army of tiny 4kB responses, so what am I doing wrong?

Courtesy of Firebug, I compared responses and noticed something peculiar, my server's JSON responses contained the entire data contents in the headers of the response itself. After some Googling, it seems response header fields have a size limit. In Firefox that limit is, you guessed it, 4096 bytes. As I found, CakePHP's automatic handling of JSON extensions takes the view variables and places them directly in the headers. Not only that, but my JSON views were returning the json_encode()'ed result of my data, so the response contained the same data in two places. Without much time available for finding a proper way to make Cake stop adding data in the headers, I decided to go back and do it the ol' fashioned way, by myself. I got rid of Cake's router line for Router::parseExtensions('json'); left my controller action alone, and changed my view to:
[php]<?php
$this->layout = 'ajax';
Configure::write('debug', 0);
header('conten-type:text/x-json');
header('cache-control:no-store,no-cache,max-age=0,must-revalidate');
echo json_encode($results);
?>[/php]
And with that, both Firefox and Chromium now accept responses greater than 4kB and 305kB respectively. I'm still sprinting to finish this project, so I haven't had time to investigate if the core Cake team knows about this issue. I plan to revisit after project launch and see if I can learn more about this strange behavior.

1 comment:

  1. Man- I wish I could've found this article a few hours ago. I just ran into this same problem today... just a few days after a site launch. The X-JSON header was so large that firebug was showing a null response from the server- even though everything worked fine in Chrome. Additionally, the issue only showed up on the production server- the dev server didn't have enough data to cause the problem. It took a few hours before I figured out(by accident) that it was the headers.

    ReplyDelete