|
YOUR FEEDBACK Did you read today's front page stories & breaking news?
SYS-CON.TV SYS-CON.TV WEBCASTS |
TOP COLDFUSION LINKS CF & Java Caching Redundant Dynamic Content With Custom Tags
Caching Redundant Dynamic Content With Custom Tags
By: Jon Block
Jun. 7, 2001 12:00 AM
What do you do when you want to get even better performance out of your most efficient application code? It can be difficult to keep total page execution time low when processing a complex page. Developers are tasked with finding ways to make apps perform better everyday. By statically storing redundant results of a dynamic page, you can get a CF site to run exponentially faster. CFHTTP, CFCACHE, and custom tags allow you to create static versions of an entire page, but only custom tags give you the flexibility to cache the results of portions of code, unleashing some awesome possibilities.
A Common Challenge
This is a situation I've been in. I wanted to make sure that each piece of my project was working at maximum capacity. My site was template-based and it became clear that each time a page was built, ColdFusion Server was doing a whole bunch of unnecessary work. The Web application had three classic features: a navigation bar that the site administrator could change by logging in; the ability to modify content on the main page of the site; and a rotating ad management system - changes that were all stored in the database (see Figure 1). The problem was that each time a visitor requested the main page, my application would query for the elements of the navigation bar, query for the main page content, and query for the banner advertising. If my site gets a million requests per day, that's 3 million queries right there. And for what? If the only thing that's changing between page re-quests is the advertising, why query for the navigation bar and the main page content over and over again? The application is running 2 million redundant queries per day. This is the point at which many CF developers would mention cached queries. However, what if you have a cluster of machines and need to run 400 hefty queries? ColdFusion can only cache 100 queries. If you're an ASP, that's not enough.
Creating Static Pages
The main problem I had with the CFHTTP method was that by creating a static version of the entire page, the resulting static page could no longer rotate banners or count banner impressions because it was no longer a .cfm file. Even if you end the resulting file with ".cfm", CFHTTP will return the same HTML content that you get when you view the source code of a page in your browser - HTML with all CFML removed. I needed to find a way to generate partially static main pages. I say "partially" because I needed to maintain my ability to manage dynamic banner ads in ColdFusion, but at the same time, reduce the load on my CF boxes. It didn't make any sense to query for the navigation bar and the main page content for each page request because that rarely changed - that was the part I wanted to be static. Also, I didn't want to deal with CFHTTP because it was a bit slow, and I would need to reconfigure my production firewall in order to get CFHTTP requests from my production servers that are directed at my load balancer to work right. The solution was in a special variable called thisTag.generatedContent, available in any closing custom tag.
thisTag.generatedContent <cf_exampleTag>In exampleTag.cfm, you can check what mode you're in by using a special variable called thisTag.-executionMode. You're in END mode only in closing custom tags, which are called when you pass a slash in the tag, like this: </cf_exampleTag>This allows you to use a CFSWITCH statement or a CFIF conditional statement in your custom tags to do certain things depending on which mode you're in. You could use the following code construct in the exampleTag.cfm: <CFIF thisTag.executionMode IS "START">Using these modes in conjunction with thisTag.generatedContent, you can grab the results of everything that happens between an opening custom tag and the corresponding closing custom tag. In the next example, I'll create a navigation bar based on a query: <cf_grabTheNavBar>There would be a variable available in </cf_grabTheNavBar>'s END execution mode called thisTag.-generatedContent, which contains the result of everything that happened between the <cf_grabThe-NavBar> and </cf_grabTheNavBar>. In this case, thisTag.generated-Content contains the resulting HTML content for the simple navigation bar: <a href="main.cfm">Main</a><br>While you're in <cf_grabThe-NavBar>'s END execution mode, you can do some cool things like change what the generated content is. In the next example, I'll take the generated content and CFFILE WRITE it to a .txt file, then clear the variable so nothing appears on the Web page. This is what my custom tag named grabTheNavBar.cfm would look like: <CFIF thisTag.executionMode IS "START">In this example, I've created a text file out of thisTag.generatedContent using CFFILE. Later, I can CFINCLUDE that .txt file on the main page of my site without having to query for it every time the page is requested. I used this technique to solve my problem. I set up my application to write off the results of the navigation bar and of the main page content when they changed. On my main page, I had two simple CFINCLUDEs that bring in the preprocessed results. This way, I no longer have to waste my resources querying to get the same information for each page build. I have to query for it only once and write it off when the site administrator makes changes. With this simple technique, I got my application to perform five times faster because the database access on my main page was reduced to banner advertisement activity only. Some other benefits of using thisTag.generatedContent instead of CFHTTP are:
Maybe you realize that by using the method described above, I make my main page vulnerable to a form of cross-site scripting. This means that the user responsible for editing site content could write ColdFusion code in the navigation bar or main page content that would be executed. For example, say the user wrote the following sentence in his or her main page content: "ColdFusion is great. My favorite tag is the <CFABORT> tag."thisTag.generatedContent would write that string to a .txt file via CFFILE, and then it would be included via CFINCLUDE when users browse the site. CFINCLUDE not only includes a file, but executes the included code as well. The <CFABORT> would be evaluated by ColdFusion Server and page processing would subsequently halt. Using CFINCLUDE can mean big problems if you CFINCLUDE any random user's saved file. Somebody could write very nasty code that could do just about anything to your file system or database. Therefore, only use CFINCLUDE when you trust the author, or you want to be able to create executable CF code from within your application. If you're concerned about unexpected ColdFusion code, one alternative that seems to work quite nicely is CFFILE READ instead of CFINCLUDE. <CFFILEThis way, the contents of your .txt file are stored in a ColdFusion variable that you simply CFOUTPUT. <CFOUTPUT>When ColdFusion code is stored inside the text content of a Cold-Fusion variable, it's not evaluated. Therefore, the <CFABORT> will never be executed by ColdFusion Server. Instead, it flows into the HTML source and is sent to the browser.
Conclusion
CFDJ LATEST STORIES . . .
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||