Changes In CFLocation / OnRequestEnd Behavior In ColdFusion 9's Application.cfc

Posted November 4, 2010 at 9:50 AM by Ben Nadel

Tags: ColdFusion

Earlier this week, Chris Long explained to me that he was able to fix a ColdFusion error in his application by adding conditional logic within the onRequestEnd() event handler for a request that performed a CFLocation. It had been understanding that a CFLocation tag aborted any further page processing. And so, when Chris told me that he was running ColdFusion 9.0.1, I wanted to see if there were any changes in the onRequestEnd() behavior between ColdFusion 9 and the earlier releases. And, as it turns, yes - the behavior of the onRequestEnd() event handler has changed in ColdFusion 9.

To test demonstrate this difference, I have created a ColdFusion Application.cfc framework component that defines the onRequestStart() and onRequestEnd() event handlers. Each of these event handlers log their own execution to a TXT file where they can be tracked across page requests:

Application.cfc

  • <cfcomponent
  • output="false"
  • hint="I define the application settings and event handlers.">
  •  
  • <!--- Define the application settings. --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = createTimeSpan( 0, 0, 1, 0 ) />
  •  
  •  
  • <!--- Define the log file path. --->
  • <cfset this.logFilePath = (
  • getDirectoryFromPath( getCurrentTemplatePath() ) &
  • "log.txt"
  • ) />
  •  
  •  
  • <cffunction
  • name="onRequestStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I intialize the request.">
  •  
  • <!--- Log the request initialization. --->
  • <cffile
  • action="append"
  • file="#this.logFilePath#"
  • output="onRequestStart: #getFileFromPath( arguments[ 1 ] )#"
  • addnewline="true"
  • />
  •  
  • <!--- Return true so the request can process. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="onRequestEnd"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="I teardown the request.">
  •  
  • <!--- Log the request end. --->
  • <cffile
  • action="append"
  • file="#this.logFilePath#"
  • output="onRequestEnd: #getFileFromPath( arguments[ 1 ] )#"
  • addnewline="true"
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

Then, I created two index files (index.cfm and index2.cfm). On the first index file, I have a link to a redirect page which relocates the user to index2.cfm. This redirect page does nothing more than invoke a CFLocation tag:

Redirect.cfm

  • <!--- Redirect to index 2. --->
  • <cflocation
  • url="./index2.cfm"
  • addtoken="false"
  • />

Once I had these files in place, I then went from the first index to the second index (by way of redirect.cfm) using both ColdFusion 8 and ColdFusion 9. Here are my results:

ColdFusion 8 - Log File

onRequestStart: index.cfm
onRequestEnd: index.cfm
onRequestStart: redirect.cfm
onRequestStart: index2.cfm
onRequestEnd: index2.cfm

As you can see, the "redirect.cfm" script execution only gets logged by the onRequestStart() event handler. In ColdFusion 8, a CFLocation tag prevents the onRequestEnd() event handler from executing. Doing the same thing in ColdFusion 9, however, yielded these results:

ColdFusion 9 - Log File

onRequestStart: index.cfm
onRequestEnd: index.cfm
onRequestStart: redirect.cfm
onRequestEnd: redirect.cfm
onRequestStart: index2.cfm
onRequestEnd: index2.cfm

As you can see, the "redirect.cfm" script execution gets logged by both the onRequestStart() and onRequestEnd() event handlers. Clearly, in ColdFusion 9, the onRequestEnd() event handler will execute after a CFLocation has been invoked.

Outside of the onRequestEnd() event handler, CFLocation still aborts any further processing of the given request. However, in ColdFusion 9, that "further processing" no longer includes the onRequestEnd() event handler. I don't use the onRequestEnd() event handler all that much in my applications, so I have no gut feeling as to whether this is a welcome change or an unexpected one. In any case, it is a change of which change you should be aware.




Reader Comments

Nov 4, 2010 at 10:21 AM // reply »
34 Comments

Hmm, interesting. Now I need to revisit what is allow in OnRequestEnd(). Could be used for certain types of authenticated apps or maybe frameworks, not sure.

But cool find and nice to know


Nov 4, 2010 at 11:02 AM // reply »
11,238 Comments

@Kevin,

I think the onRequestEnd() provides some excellent hooks for logging since you flush the content to the client so as not to slow down their "experience."


Nov 4, 2010 at 11:48 AM // reply »
51 Comments

Nice catch Ben. Do you know if this was an intentional change in CF9 or a bug?

If its intentional it opens up all sorts of nice things such as logging, but on the flipside it could break a lot of things too.

I remember seeing a code example where the author called a page header from the onRequestStart and the page footer from the onRequestEnd method.


Nov 4, 2010 at 11:48 AM // reply »
18 Comments

Ben, Thanks for sharing and in my opinion, this is the correct behaviour in CF9. This gives much more control on how and what you want to achieve in onRequestEnd function and this way you are sure if you want to log anything in onRequestEnd method, that would be logged.

Cheers

Philip


Nov 4, 2010 at 12:07 PM // reply »
15 Comments

+1 to @Philip


Nov 4, 2010 at 12:56 PM // reply »
18 Comments

@Aaron,

Thanks Aaron.

Cheers

Philip


Nov 4, 2010 at 1:04 PM // reply »
18 Comments

@Aaron,
This is in reply to your blog about sorting:
http://aarongreenlee.com/share/sort-array-of-objects-in-coldfusion/

I enhanced a function about complex array sorting in CF. Did you find my blog when you searched for it, please have a look here and let me know what you think?

http://philipbedi.wordpress.com/2010/08/04/complax-array-sorting-in-coldfusion/

Sorry Guys, its off the topic, but I can't find a way to reply on Aaron's blog. Aaron, did you turn off commenting on your blog?

Philip


Nov 4, 2010 at 2:24 PM // reply »
11,238 Comments

@Steven,

My guess is this is considered a "fix". I think there were a number of people who felt that the onRequestEnd() should always be called since the requests does, technically, always "end" at some point.

I think it definitely has the potential to break existing code, or so create odd behavior. I think that's why it's critical for people to be aware of it.

I've got some more testing I'd like to do with it.

@Philip, @Aaron,

I think it makes sense, to a degree, that this always fires. I'm reserving full judgment until I do a bit more testing.


Nov 4, 2010 at 3:11 PM // reply »
2 Comments

Just to clear this up, is the rest of the template executed?

If your redirect.cfm page had:

<cflocation url="./index2.cfm" addtoken="false" />
<cffile action="append" file="log.txt" output="Hello!" addnewline="true" />

...the template stops running and the "Hello!" wouldn't be appended?

And... is there any difference to the <cfheader statuscode="301" /> behavior?


Nov 4, 2010 at 3:52 PM // reply »
11,238 Comments

@Geoff,

I had that exact same thought this morning and did double check the behavior. Trying to log to the file right after the CFLocation did *not* result in anything be written to the log file. So, it seems that only the onRequestEnd() actually get's fired.

According to what I found before, CFLocation is definitely different from simply executing a CFHeader/302/301 header:

http://www.bennadel.com/blog/1550-Performing-ColdFusion-Processing-After-A-CFLocation-Tag.htm


Nov 11, 2010 at 5:13 AM // reply »
9 Comments

Yep, this broke some functionality on our site where we were storing user messages in a persistent scope and then calling cflocation before clearing out the message on the onRequestEnd() on the subsequent page.

Now that onRequestEnd() fires even though we've redirected our message gets cleared immediately!

We'll work around it but in my opinion this is not a 'fix' as described in their release notes but a change in behaviour.


Nov 16, 2010 at 4:44 PM // reply »
1 Comments

Thanks Ben for posting this. We were trying to figure out how come all of our CFLocation tags stopped working after we upgraded our CF8 server to CF9 for the past few weeks.

The CFLocation tag was appending the same path twice to the end of the URL, causing the redirects to break. We stopped using the OnRequestEnd() and now CFLocation is working again.

By the way, it was great meeting you at CFUnited.


Jan 7, 2011 at 3:26 PM // reply »
11,238 Comments

@Ciaran,

Yeah, I am not sure this is much of a "fix" either. I suppose it makes sense, since your request is "ending"; but at the same time, you could also argue that for a CFAbort tag as well.

@Susan,

Great to meet you as well :)


Mar 18, 2011 at 2:38 PM // reply »
1 Comments

What was that conditional logic that Chris Long explained? I wanted to try to use it in an application.cfc onRequestEnd() to determine when a CFLocation was executed. I am using CF8 and don't have the "fix" from CF9.


Apr 8, 2011 at 8:45 AM // reply »
3 Comments

Yeah, this has just stung us after our company upgraded to 9.0.1.

I've posted this description of the problem, together with a request for a change:

http://forums.adobe.com/thread/835623


Jun 7, 2011 at 10:12 AM // reply »
31 Comments

Maybe this just slipped under my radar but I completely missed this change. Totally confused me when I was helping someone out with an app being redeveloped on CF9.

@Ben, didn't see much mention in your post about CFAbort behaving the same way (onrequestend still executes). But that's what I ran into as well.

It makes sense to me to have this behaviour as it'll be useful for having somewhere to put code for the end of literally any request. The problem I have is I'd like to know what happened to that request. Was it normal, a redirect, a cfabort... Is Cfcontent the same when used for a download? Be nice to have an extra argument in onRequestEnd(targetPage, abortType=[normal|abort|location|content|other])

I ended up recreating the old behaviour by creating a request scope variable at the very end of my onRequest method. Then testing for it's existence in onRequestEnd and aborting if it's not there.


Jun 28, 2011 at 10:35 PM // reply »
11,238 Comments

@David,

Wait, you're saying that CFAbort *also* allows the onRequestEnd() event handler to fire in CF 9+... hmm. I'll have to test that one with my own eyes in the morning :)


Jun 29, 2011 at 10:43 AM // reply »
11,238 Comments

@David,

Wow - I just tested what you said about CFAbort:

http://www.bennadel.com/blog/2221-CFAbort-And-OnRequestEnd-Behavior-In-ColdFusion-8-And-ColdFusion-9.htm

I can't believe that's actually true. This feels very much like a bad move to me.


Sam
Oct 3, 2012 at 11:07 AM // reply »
1 Comments

I don't think it is a bad move.

CF8 had the bug of not executing the onRequestEnd, and has now been fixed in CF9.

To clarify the meaning of CFAbort. It is to stop the further execution of the code in the page. Yes. It stops what it says, but the control has to still get passed on to finish the page request. So, it is perfectly plausible to continue the call to onRequestEnd.

I definitely see this as a good move in CF9.

Offcourse the different behavior when compared to CF8 can cause some issues to some applications, but they have to correct it as the bug in CF8 is now fixed.


Oct 10, 2012 at 3:24 PM // reply »
19 Comments

Yes, I was aware of this change from 8 to 9. Personally, it seems more 'logical' that onRequestEnd fires after the primary event is 'aborted'. Similar to the cfexit/exit context options, it would be nice to have an option to make it abort 'all' events of the request.

Additionally, I found the onReqeustEnd() event fires twice if you abort while in the event itself. Happily it does not create an infinite loop:
http://www.wbq.us/www_wbq_us/index.cfm/blog/cf9-onrequestend-fires-twice/.



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools