204 Status Codes And ColdFusion CFHttp Calls

Posted December 4, 2007 at 9:50 AM

Tags: ColdFusion

The other day, in a comment to my caveman-style asynchronous ColdFusion page execution, JAlpino told me to look into the use of the 204 status code to help the CFHttp call return faster. I haven't done a ton with different status codes (mostly 200 and 301/302), so I did a quick Google search for status code 204. According to this page, the 204 status code represents a page that has no content:

204 No Content. This code is used in cases where the request was successfully processed, but the response doesn't have a message body.

According to JAlpino, when a browser receives this status code in the header, it closes the request because it thinks the request will not render any content. In the context of a CFHttp call, the hope is that the CFHttp request will close out immediately and allow the parent ColdFusion page to continue executing with little delay.

To test this, I set up a small ColdFusion page with a 204 status code definition:

 Launch code in new window » Download code as text file »

  • <!---
  • Tell the browser there is no content by using the
  • status code, 204 - No content.
  • --->
  • <cfheader
  • statuscode="204"
  • statustext="No Content"
  • />
  •  
  • <!--- Set the content type and reset the output stream. --->
  • <cfcontent
  • type="text/html"
  • reset="true"
  • />
  •  
  • <!--- Flush headers. --->
  • <cfflush />
  •  
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>Status Code Test: 204 No Content</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Status Code Test: 204 No Content
  • </h1>
  •  
  • <p>
  • There is content on this page, but the header
  • information should tell the browser that no
  • content could be found.
  • </p>
  •  
  • <!---
  • To make sure that the page doesn't execute
  • instantaneously, let's get the page to sleep
  • for a few seconds.
  • --->
  • <cfthread
  • action="sleep"
  • duration="#(5 * 1000)#"
  • />
  •  
  • <p>
  • Done building page.
  • </p>
  •  
  • </body>
  • </html>

Here, you can see that I am setting the status code to 204 using ColdFusion's CFHeader tag. Then, I flush the header to make sure we don't build the whole page on the server before returning the header data. To make sure that this header status works, I am sleeping the page for 5 seconds, which would be a noticeable delay in the calling page.

Then, I set up a ColdFusion page to execute a CFHttp request to the 204.cfm page I built above:

 Launch code in new window » Download code as text file »

  • <!--- Get the page that we want to call. --->
  • <cfset strURL = (
  • GetDirectoryFromPath(
  • "http://#CGI.server_name#:8#CGI.script_name#"
  • ) &
  • "204.cfm"
  • ) />
  •  
  •  
  • <!--- Mark the time that we are starting the request. --->
  • <cfset intStartTick = GetTickCount() />
  •  
  • <!---
  • Grab page that we know has a 204 no content header
  • and a long delay. This will test to see how fast the
  • CFHttp call returns based on header information.
  • --->
  • <cfhttp
  • url="#strURL#"
  • method="get"
  • result="objGET"
  • />
  •  
  •  
  • <!--- Output time to wait. --->
  • <cfoutput>
  •  
  • <p>
  • Wait Duration:
  •  
  • #DecimalFormat(
  • ((GetTickCount() - intStartTick) / 1000)
  • )#
  •  
  • Seconds
  • </p>
  •  
  • <p>
  • Content: [#objGET.FileContent#]
  • </p>
  •  
  • </cfoutput>

After the ColdFusion CFHttp quest returns, I am outputting the time of execution as well as the content that was returned. The execution time is obvious, but the content I am outputting to make sure that the CFHttp really does cut out of the request before the page is fully rendered.

When I run the calling page, I get the following output:

Wait Duration: 5.01 Seconds

Content: []

Ok, so what does this tell us? The 5.01 second execution time tells us that the CFHttp call did have to wait for the CFThread call on the 204.cfm template. But, the empty content tells us that the CFHttp call did not bring back any content with it. In a way, these are two conflicting properties of the call. It should have either returned instantly with no content, or it should have returned after 5 seconds with the content of the 204.cfm template.

At first, I thought that JAlpino was simply wrong in his assessment of how a 204 status code would interact with a ColdFusion CFHttp call. But the fact that we have conflicting behaviors as defined above didn't sit well with me. I kept going over it in my mind, and then I realized what the problem was: CFFlush!

CFFlush, as amazing of a tag as it is, is a bit buggy when it comes to flushing minimal amounts of data. If you look at where we are calling CFFlush in our 204.cfm ColdFusion template, you will notice that it is before any HTML and just after we cleared the output stream (content buffer). As such, at that point, we'd be flushing a few spaces and maybe a line return at best. CFFlush, however, doesn't always like to flush so little data.

To experiment, I moved the CFFlush to right after the doc type declaration:

 Launch code in new window » Download code as text file »

  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <!--- Flush headers. --->
  • <cfflush />
  • <html>

Now, the hope is that the text characters in the doc type would provide enough data such that the ColdFusion server would be happy to fully execute the CFFlush command. And indeed, running the page again, we get the following output:

Wait Duration: 0.02 Seconds

Content: []

Ok, now we're getting the results that we were hoping for. Looks like JAlpino dropped a great tip on me; using a status code of 204 will allow the ColdFusion CFHttp call to return much faster than the 1 second timeout hack that I was using. We just have to be very careful on how soon the Headers are flushed to the client.

And, on a related note, this just goes to show you how important it is to have a framework that allows CFFlush in the page rendering. Case in point, if you want to leverage header values before the page has fully rendered, you need to allow it.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page





Reader Comments

Dec 4, 2007 at 11:49 AM // reply »
15 Comments

Nice write up Ben! As usual, you go above an beyond in your research and gratefully share it with the rest of us. I've typically used 204 status codes instead of AJAX requests when it wasn't (absolutely) necessary to receive a response from the server, items like 'watch this item' or 'flag this site' kind of situations. - Justin


Dec 4, 2007 at 11:51 AM // reply »
7,538 Comments

@Justin,

That sounds like a good technique. And sorry about calling you JAlpino - I didn't know what your first name was :) Thanks for the hot tip and glad that I could echo it back out there.


Dec 4, 2007 at 1:28 PM // reply »
15 Comments

@ Ben, no problem about the name thing, I usually sign with JAlpino instead of my full name. Here is the article that I first learned about using 204 for async processing (http://cfdj.sys-con.com/read/46789.htm). This article piqued my interest in learning more about status codes and various request\response headers.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 17, 2010 at 4:13 PM
Testing For NULL Values In A ColdFusion Query Result Set
To get around the empty strings in an UPDATE statement I pretended the variable was a string by enclosing it in single quotes, CAST it to an integer, let it convert empty strings to zeroes, and used ... read »
Mar 17, 2010 at 4:12 PM
Ask Ben: Environment-Based Application.cfc Settings
Ben, those are valid comments. I posted some code that shows how to "worryfree ;o)" copy code and let the Application.cfc sort it out. http://boncode.blogspot.com/2010/03/cf-dynamically-changing-ap ... read »
Mar 17, 2010 at 3:32 PM
Using Appropriate Status Codes With Each API Response
@Marc, For our project it isn't really a requirement, since most (if not all) of our resources are private and related to the logged in user. Anyway, IIRC google does execute javascript before inde ... read »
Mar 17, 2010 at 3:24 PM
Finally Finished Ayn Rand's Atlas Shrugged Audio Book
Objectivism is a form of positivism, and Quantum Mechanics does not fit positivism. One of the postulates of Quantum Mechanics is the impossibility of separating the object of measurement from the me ... read »
Mar 17, 2010 at 2:52 PM
Ask Ben: Blocking WSDL Access In A ColdFusion Application
<cfif structKeyExists( url, "wsdl" ) and not structKeyExists( url, "x")> should fix that ... read »
Mar 17, 2010 at 2:43 PM
Ask Ben: Blocking WSDL Access In A ColdFusion Application
You are correct. You can use HTTPservice RPC model instead and not worry about the wrapper. Not too much harder to do but not as extensible or fun! I wonder if the Flex app could pass an arg after t ... read »
Mar 17, 2010 at 2:40 PM
Using Appropriate Status Codes With Each API Response
Simon, If you're serving up what is essentially a blank page "template", and then getting the actual content for that page using javascript, how on earth are you getting the search engines to see yo ... read »
Mar 17, 2010 at 2:34 PM
Using Appropriate Status Codes With Each API Response
We have a similar setup as Rocky. We have a backend which only exposes REST services. It doesn't output any html, js, jsp, .. . (We are capable of running jsp, groovy, jsf, ruby, jython, etc.. but w ... read »