You already have learned that ColdFusion allows you to cache query results. It also provides a page-caching feature, which enables you to cache the complete HTML page that each of your templates generates. Similar to query caching, ColdFusion's page-caching feature is designed to improve your Web pages' overall performance.
The idea is simple. If you have certain ColdFusion templates that are time-consuming or get hit often, you can tell ColdFusion to cache them for a specified period of time. This can have a huge effect on overall application performance. The caching can take place on the browser machine, on the server machine, or on both.
Introducing the <cfcache> Tag
If you want ColdFusion to cache a page, place the <cfcache> tag at the top of the template, before any other CFML or HTML tags. The most important attribute for the <cfcache> tag is the action attribute, which tells ColdFusion whether you want the page cached on the client machine, on the ColdFusion server machine, or on both.
Client-Side Page Caching
The <cfcache> tag can provide two types of caching: client-side page caching and server-side page caching. Both are of great benefit. Let's look first at client-side page caching, which is of particular relevance when you're putting together personalized pages that might take some time to display. Then we will look at server-side page caching, which is most useful for putting together non-personalized pages that get hit very often.
Finally, we will see how to use client-side and server-side page caching together, usually the best option.
All modern Web browsers provide some type of internal page-caching mechanism. As you use your Web browser to visit sites, it makes local copies of the HTML for each page, along with local copies of any images or other media files the pages contain. If you go back to that same page later, the browser will show you the local copies of the files, rather than refetching them from the Web server. Your browser also provides settings you can use to control where the cached files are kept and how large the collection of all cached files can get. If it weren't for your browser's cache, most casual Web browsing would be much slower than it is.
Normally, the browser just relies on these settings to determine whether to display a page from its local cache or to recontact the Web server. If you haven't adjusted any of these settings, your own browser is probably set to use the cached copy of a page until you close the browser. When you reopen the browser and visit that same page, the browser recontacts the Web server and fetches the page afresh.
To view the current cache settings for a Firefox browser, choose Tools > Options > Privacy > Cache. For Internet Explorer, choose Internet Options from the Tools menu, then click the Settings button under Temporary Internet Files.
Gaining More Control
The <cfcache> tag gives you programmatic control over when the browser should use its local, cached copy to display a page to the user. You use the timeSpan attribute to tell ColdFusion how old the browser's cached version of the page can be before ColdFusion should refetch it from the server. If the browser fetched its local copy of the page after the date you specify, it uses the local copy to show the page to the user. If not, it visits the template normally. Table 25.2 summarizes the attributes relevant for this use of the <cfcache>.
For instance, if you wanted the browser to use its local copy of a page for six hours at a time, you would include the following at the top of your ColdFusion template:
<!--- Let browser use a cached version of ---> <!--- this page, from up to six hours ago ---> <cfcache action="ClientCache" timeSpan="0.25">
If you wanted to cache all pages in an application, you could simply place the <cfcache> tag in your Application.cfc file. That would cause all page requests to be cached (except for form submissions, which never are).
The first time a user visits the page, ColdFusion processes the template normally and sends the generated page back to the browser. The browser then stores the page in its local cache. The next time the user visits the same page, the browser quickly contacts the server, providing the server with the exact date and time that the page was visited the first time (that is, the date and time the local copy was saved). If the browser tells the server that its local copy is not older than the date specified in timeSpan, the server then tells the browser to show the local copy to the user and immediately stop processing the rest of the template. Otherwise, ColdFusion tells the browser that the local copy is now out of date; processes the rest of your code normally; and returns the newly generated version to the browser, where it can be cached locally for the next six hours (or whatever interval you specify).
What It Means
By using <cfcache>, you can keep the amount of interaction between the browser and server to a minimum. Yes, the browser will contact the Web server, and ColdFusion will begin executing your template code. But as soon as ColdFusion encounters the <cfcache> tagwhich should be at the top of your CFML codeColdFusion will often be able to tell the browser to just use its local copy of the page. This is a fast operation because only the initial handshake between browser and server is necessary to determine whether the local copy can be used.
This improves performance in three important ways:
With Netscape browsers, you can override the client-side cache for a particular page request by doing what Netscape calls a super reload (which means holding down the Shift key while clicking the browser's Reload button). This can be useful for testing your pages. You can do the same with most versions of Internet Explorer by holding down the Ctrl key (or equivalent) while clicking the browser's Refresh button.
Server-Side Page Caching
You can also use the <cfcache> tag to enable ColdFusion's server-side page caching mechanism. Like client-side caching, this method takes advantage of a previously generated version of your template code. However, server-side caching doesn't use the cached copy of the page that might be on the browser machine. Instead, it looks for a cached copy of the page that ColdFusion stores on the server's drive.
Enabling Server-Side Caching
To enable server-side caching for one of your templates, place a <cfcache> tag at the top of the template before your other CFML and HTML tags. As you can see in Table 25.3, a number of attributes are relevant for using <cfcache> to do server-side caching. They are all optional, however, and most of them are relevant only if your template is secured via SSL encryption or a user name and password. Most of the time, you can just specify action="ServerCache" and whatever timeSpan you desire.
For instance, you could place the following snippet at the top of any of your ColdFusion templates. It tells ColdFusion that your template code only needs to execute once every 30 minutes at most:
<!--- Let browser use a cached version of ---> <!--- this page, from up to six hours ago ---> <cfcache action="ServerCache" timeSpan="#createTimeSpan(0, 0, 30, 0)#">
The first time the template is accessed, ColdFusion processes your code as it would normally do. But before it sends the generated page back to the browser, it also saves the page as a separate, static file on the server's drive. The next time the page is accessed, ColdFusion simply sends back the static version of the file without executing any code that appears after the <cfcache> tag. ColdFusion will continue to send this static version back to all visitors until 30 minutes have passed. After the 30 minutes have elapsed, the next page request reexecutes your template normally.
For most situations, that's all you have to do. Your visitors will immediately begin to see improved performance. The more often your pages are hit and the longer your template code takes to execute, the larger the benefit.
Listing 25.2 is a simple example that demonstrates this effect. The template uses the timeFormat() function to output the current time. At the top of the template, the <cfcache> tag allows the page to be cached for 30 seconds at a time. Try visiting this page repeatedly in your browser.
Listing 25.2. ServerSideCache.cfmTesting the Server-Side Cache Mechanism
<!--- Filename: ServerSideCache.cfm Author: Nate Weiss (NMW) Purpose: Demonstrates use of server-side caching ---> <!--- Cache this template for 30 seconds at a time ---> <cfcache action="ServerCache" timespan="#createTimeSpan(0, 0, 0, 30)#"> <html> <head><title>Caching Demonstration</title></head> <body> <!--- Display the current time ---> <p>This page was generated at: <cfoutput>#timeFormat(now(), "h:mm:ss tt")#</cfoutput> </body> </html>
The first time you visit this template, it displays the current time. For the next 30 seconds, subsequent page accesses will continue to show that same time, which proves that your template code is not re-executing. Regardless of whether you access the page using another browser or from another machine, click the browser's Reload or Refresh button, or close and reopen the browser, you will continue to see the original time message until the 30 seconds have elapsed. Then the next page request will once again reflect the current time, which will be used for the next 30 seconds.
Remember, if you are using <cfcache> for server-side caching (that is, with an action of Cache or ServerCache), the page won't be regenerated for each user. In particular, you should make sure that the page doesn't depend on any variables kept in the CLIENT, COOKIE, or SESSION scopes because the generated page will be shared with other users, without checking that their CLIENT, COOKIE, or SESSION variables are the same. So in general, you shouldn't cache personalized pages using server-side caching. For personalized pages, enable client-side caching with action="ClientCache" instead.
So far, you have learned about client-side page caching (that is, using <cfcache> with action= "ClientCache") and server-side page caching (action="ServerCache").
As noted earlier in Tables 25.2 and 25.3, you can use both types of caching together by specifying action="Cache" or by omitting the action attribute altogether. For each page request, ColdFusion will first determine whether the browser has an appropriate version of the page in its local cache. If not, ColdFusion determines whether it has an appropriate version of the page in its own server-side cache. Only if there isn't an appropriate version in either cache will your template code re-execute.
The result is greatly enhanced performance in most situations.
In previous versions of ColdFusion, the default value for action resulted in server-side caching only. In ColdFusion, the default is for both types of caching to be enabled. So if you move an application to ColdFusion and the code doesn't provide an action attribute, the server-side cache and client-side caches will both be enabled. This shouldn't be a problem, since nearly any situation that would benefit from server-side caching will also benefit from client-side caching as well.
Caching Pages That Use URL Parameters
ColdFusion maintains a separate cached version of your page for each combination of URL parameters with which it gets accessed. Each version expires on its own schedule, based on the timeSpan parameter you provide. In other words, you don't need to do anything special to employ server-side caching with pages that use URL parameters to pass ID numbers or any other information.
ColdFusion doesn't cache the result of a form submission, regardless of whether the target page contains a <cfcache> tag, so <cfcache> is disabled whenever the CGI.request_method variable is set to POST.
Remember, if you are using <cfcache> for server-side caching, the page won't be regenerated for each user, so server-side caching shouldn't be used for pages that are personalized in any way. The only type of caching that is safe for personalized pages is client-side caching (action="ClientCache"). See the important caution in the previous section.
Specifying the Cache Directory
By default, ColdFusion stores the cached versions of your templates in a folder called cache, located within the ColdFusion installation directory. If after visiting Listing 25.2, you look in the directory where you saved the listing, you will notice that ColdFusion has placed a file there, with a .tmp extension. If you open this .tmp file in a text editor, you will see that it contains the final, evaluated code that the ColdFusion template generated. A new .tmp file will appear in the folder whenever you visit a different template that uses server-side caching. In addition, a different .tmp file will appear for each set of URL parameters supplied to the templates when they are visited.
If you want to store the .tmp files in some other location, you can use the directory attribute to tell ColdFusion where to store them. You must provide a fully qualified file path to a folder on your server's drive (or on a local network, although this is not recommended).
For instance, the following would tell ColdFusion to store its cache files in a folder called cachefiles:
<!--- Cache this template for 30 seconds at a time ---> <cfcache action="Cache" timeSpan="#createTimeSpan(0,0,0,30)#" directory="c:\cachefiles">
You would, of course, need to create the cachefiles directory on the server machine before this would work.
The directory value shouldn't be within the Web server's document root. You don't want people to be able to request the .tmp files directly via their browsers.
Flushing the Page Cache
Earlier in this chapter, you learned about query caching and how to make a cached query refresh when the data in the underlying database tables change. You have the same option for server-side page caching, via the flush action provided by the <cfcache> tag. You can also delete ColdFusion's cache files manually.
To flush a page from the cache before it would time out on its own, simply use the <cfcache> tag with action="flush". Table 25.4 shows the attributes relevant for flushing the server-side page cache.
If one of your templates makes some type of change that your application should reflect immediately, even in pages that would otherwise still be cached, you could use the following line to delete all cached pages in the current directory. You would place this code in the change template, right after the <cfquery> or whatever else is making the actual changes:
<!--- Flush the server-side page cache ---> <cfcache action="Flush">
If you don't need to expire all cached pages from the directory, you can provide an expireURL attribute. For instance, suppose you are using server-side caching to cache a template called ShowMovie.cfm, and that movie accepts a URL parameter called FilmID. After some kind of update to the Films table, you might want to flush the ShowMovie.cfm template from the cache, but only for the appropriate FilmID. To do so, you might use code like the following:
<!--- Flush the server-side page cache ---> <cfcache action="Flush" expireURL="ShowMovie.cfm?FilmID=#FORM.FilmID#">
Or to flush the cache for all versions of the ShowMovie.cfm template (regardless of URL parameters), leaving all other cached pages in the directory alone, you would use something like this:
<!--- Flush the server-side page cache ---> <cfcache action="Flush" expireURL="ShowMovie.cfm?*"> Controlling White Space
One of the side effects of CFML's tag-based nature is the fact that white-space characters (such as tabs, spaces, and return characters) that you use to indent your CFML code are usually passed on to the browser as part of the final generated page. In certain cases, this white space can considerably inflate the size of the generated HTML content, and this in turn can hurt performance. ColdFusion provides several options for dealing with these extraneous white-space characters.
ColdFusion's ability to automatically control white space is better than ever in ColdFusion. You will find that in most cases, you can just enable the automatic Whitespace Management feature (discussed in a moment) and never think about white space issues again. Nonetheless, it is worthwhile to discuss the other options available to you, just in case.
Understanding the Issue
In a ColdFusion template, you use CFML and HTML tags together. The processing instructions for the server are intermingled with what you actually want to generate. That is, there is no formal separation between the code and the content parts of your template. Most other Web scripting environments separate code from content, generally forcing you to put the HTML code you want to generate into some type of Write() function or special block delimited by characters such as <% and %> (depending on the language).
The fact that you get to use CFML tags right in the body of your document is a big part of what makes ColdFusion development so powerful, but it has a disadvantage. Often ColdFusion can't easily determine which white space characters in a template just indent the code for clarity and which should actually be sent to the browser as part of the final, generated page. When Cold Fusion can't make the distinction, it errs on the side of caution and includes the white space in the final content.
Automatic White-Space Control
The good news is that ColdFusion already does a lot to eliminate excess white space from your generated pages. ColdFusion includes an automatic white-space elimination feature, enabled by default. As long as you haven't disabled this feature, it's already pulling much white space out of your documents for you, before the generated page is sent to the browser.
Enabling White-Space Suppression
On the Settings page of ColdFusion Administrator, you'll see an option called Enable Whitespace Management. When this is enabled, portions of your template that contain only CFML tags will have the white space removed from them before the page is returned to the browser. Basically, ColdFusion looks at the template, finds the areas that contain only CFML tags, removes any white space (extra spaces, tabs, indents, new lines, or hard returns) from those areas, and then processes the template.
It's easy to see this in action. To do so, follow these steps:
If you compare the two versions of the page source, you will see that the second (or first) version has a lot more blank lines and other white space in it. In particular, it has a lot more space at the very top, consisting of all the white space that surrounds the comments and various <cfquery>, <cfparam>, and <cfset> tags at the top of Listing 25.1. The first version of the page source has eliminated that white space from the top of the document.
There are very few situations in which this automatic suppression of white space would be undesirable. In general, you should leave the Enable Whitespace Management option enabled in Cold Fusion Administrator.
Controlling White-Space Suppression Programmatically
You can turn off ColdFusion's automatic white-space suppression feature for specific parts of your document. Such situations are rare because HTML usually ignores white space, so there is generally no need to preserve it.
However, in a few situations you wouldn't want ColdFusion to remove white space for you. For instance, a few rarely used HTML tags like <pre> and <xmp> do consider white space significant. If you are using either of these tags in a Web document, ColdFusion's white-space suppression might eliminate the very space you are trying to display between the <pre> or <xmp> tags. You might run into the same problem when composing an email message programmatically using the <cfmail> tag (see Chapter 27, "Interacting with Email").
In such a situation, you can use the suppressWhitespace="No" attribute of the <cfcfprocessingDirective> tag to disable the automatic suppression of white space. Place the tag around the block of code that is sensitive to white-space characters, like so:
<cfprocessingDirective suppressWhitespace="No"> <pre> ...code that is sensitive to white space here... </pre> </cfprocessingDirective>
For details, see the <cfprocessingDirective> tag in Appendix B, "ColdFusion Tag Reference."
Suppressing White-Space Output with <cfsilent>
Unfortunately, ColdFusion can't always correctly identify which parts of your code consist only of CFML tags and should therefore have white space automatically removed. This is most often the case with code loops created by <cfloop> and <cfoutput>.
If you find that a particular portion of code generates a lot of unexpected white space, you can add the <cfsilet> tag, which suppresses all output (even actual text and HTML tags). The <cfsilent> tag takes no attributes. Simply wrap it around any code blocks that might generate extraneous white space when executed, such as <cfloop> or <cfoutput> loops that perform calculations but don't generate any output that the browser needs to receive.
The <cfsilent> tag doesn't just suppress white-space output. It suppresses all output, even output you would generally want to send to the browser (such as HTML code and text).
Suppressing Specific White Space with <cfsetting>
For situations in which ColdFusion's automatic suppression isn't suppressing all the white space in your generated pages (for instance, the first <cfloop> snippet in the previous section), but where <cfsilent> is too drastic, you can use the <cfsetting> tag to suppress output in a more selective manner.
The <cfsetting> tag takes a few optional attributes, but the only one relevant to this discussion is the enableCFOutputOnly attribute. When this attribute is set to Yes, it suppresses all output (similar to how the <cfsilent> tag works), except for <cfoutput> blocks. Any HTML code or text that should be sent to the browser must be between <cfoutput> tags, even if the code doesn't include any ColdFusion variables or expressions. This is different from ColdFusion's normal behavior, where it assumes that it can send any non-CFML text or code to the browser.
So if you find that a section of code is generating a lot of white space, but you can't easily use<cfsilent> because your code must be able to generate some output, then you should place a <cfsetting> tag with enableCFOutputOnly="Yes" just above the section of code, and a <cfsetting> tag with enableCFOutputOnly="No" just below the section. Within the section of code, make sure <cfoutput> tags surround any item (even plain text) that you want to include in the final, generated version of the page. This gives you complete control over all generated white space and other characters.
Note that when you use <cfsetting> to control white space, it acts like a "stack." What do we mean by that? If you have two or more <cfsetting> tags, both of which turn on enableCFOutputOnly, you can imagine that ColdFusion has an internal value of 2 for suppressing white space. This means you would need to turn off the setting twice in order to return to the default behavior. The upshot? Be sure to always switch this setting off after turning it on, even if it is at the end of the page.
See Appendix B, "ColdFusion Tag Reference," for more information about the <cfsetting> tag.