Transcript Slide 1

Exception Handling
MDCFUG 6/12/2007
David Lakein
Programmer / Analyst
TeraTech Inc.
About Me
• Application Developer at TeraTech since
1998
• Working in ColdFusion since 1999,
CF4.01
• Certified Advanced CF7 Developer
What’s wrong with this picture?
The Problem
• Too much info gets shown to users
– Embarrassing
– Could be security hazard
• Site admins/developers need notification,
enough useful debugging info to find the
error and be able to fix
– Users won’t send it to you, and you don’t want
them seeing it anyway!
What this presentation will cover
• Different types of errors
• Language features used to catch and
handle
– Overview of properties
– Suggestions for usage
• Creating a simple customizable general
error handler
What this will not cover
• Won’t cover all details and properties of
cfcatch and error object
• Check out the references at the end
Types of errors
• Exception: Error that doesn’t allow the request to
continue.
– You can catch the error, and CF gives you a structure with error
details.
• Types/examples of errors:
–
–
–
–
–
–
Parse/Compile error: malformed CF tags
Syntax error: missing property
Runtime: won’t be found until code executes
Validation: server-side form validation
System: connection fails
Request: URL that user requested doesn’t exist
• Not a CF exception, but CF can handle
• Different from CF’s CFError type=Request
– Logic errors: don’t directly cause an exception, but are still wrong
Error: Parse
• ColdFusion first parses the templates, then
compiles into Java. If CF cannot parse the
syntax, there is little useful it can do with it.
• If it’s in the main request page, won’t be caught
by CFCatch, CFError, or OnError!
– Goes straight to server-wide error handler
– Will be caught properly if parse error happens in an
include (lower level than the error handler)
<cfif 1 eq 3>
I have no closing cfif tag.
Error: Syntax
• Code can be parsed, but language use is wrong,
which may prevent it from being compiled.
• e.g., Missing required attributes or arguments,
invalid parameters
<cfbad>
CF will say: "Unknown tag: cfbad.
ColdFusion cannot determine how to
process the tag cfbad because the tag
is unknown and not in any imported tag
libraries. The tag name might be
misspelled…"
</cfbad>
Error: Runtime
• Errors that happen when the code is executing
• This covers most other kinds of code errors
– Error responses from outside CF
• CFHTTP calls
• Database
– CFML errors
• Undefined variables
• CFThrow creating a custom exception type
• CFAbort with “showerror” attribute
• E.g., Value set in in a variable at runtime is the
wrong type for a function argument, if it has a
type.
Error: Validation
• CF has basic built-in server-side form validation fields; e.g., hidden
fields named “fieldname_required” or “fieldname_type”.
• If the submitted data fails, CF throws a Validation error.
• Similar feature will be generated by CF7's CFInput
validateAt="onServer"
• Depends on the extra hidden form fields submitted by client
<input type="text" name="firstname" />
<input type="text" name="age" value="Twenty" />
<input type="hidden“ name="firstname_required"
value="First name is required."/> <br/>
<input type="hidden“ name="age_integer" value="Age
must be an integer." />
Error: System
• Type of runtime error
• Bad connection to db
• File is missing
Reducing Details Shown By Default
• Turn off Robust Exception Information to reduce
what gets shown to the user if an error isn’t
handled, or if the exception handler fails.
Where CF Handles Errors
• Server-wide error handler
• Server-wide missing template handler
– HTTP 404 error
• CFError tag
– Catches unhandled errors anywhere after the point where it is
defined
• Application.cfc onError event (CF7+)
• Application.cfc onMissingTemplate event (CF8, in public
beta)
– Local HTTP 404 handler
• CFTry/CFCatch
– Catch errors right around the code they happen
Server-wide error and 404 handlers
•
Missing Template handler: URL from root of the website
–
–
•
HTTP 404 errors
Browser requests CF page that doesn’t exist; webserver passes to ColdFusion to handle.
Site-wide error handler: ColdFusion path, including mappings, from root.
–
Template that is executed whenever an error is not handled at the application or code level.
CFError
• Catches unhandled errors anywhere
after the point where it is defined
• Declare anywhere in cfm pages. Should
be near the top of the Application.cfc or
Application.cfm
• Object named “Error” – error details,
stack trace, location, templates called
CFError (cont’d)
• Attributes:
– Template: CF relative or absolute mapping path to the
error handler template
– Type
– Exception (optional): specific type to catch
– Mailto (optional): passes in as error.mailTo
• Type:
– Type=“Exception” – full exception handler.
– Type=“Request” – errors that fail exception handler.
Limited; can only output Error variables.
– Type=“Validation” – CF form validation. Limited like
Request type.
CFError example
• Application.cfm
<cferror type="exception“ template="exception.cfm“
mailTo="[email protected]">
• sample.cfm
<h1>Example: cferror in Application.cfm, mail to
admin.</h1>
<!--- Undefined variable, will cause an error --->
<cfoutput>#NonExistentVariable#</cfoutput>
<h3>Since we are using cferror type="Exception",
html after the error will not appear,
and html before the error will only show in
Error.GeneratedContent.
</h3>
CFError example (cont’d)
• Exception.cfm
<!--- Default address to send to --->
<cfset mailto=“[email protected]">
<cfif structkeyExists(Error, "mailto") AND Len(error.Mailto) GT 0>
<cfset mailto = Error.mailto>
</cfif>
<cfmail server=“mailserver.domain.com"
from="[email protected]" to="#mailto#"
subject="Error in Example App on #CGI.HTTP_HOST#"
type="html">
<h4>ERROR In page: #Error.Template#<h4>
<cfdump var="#error#" label="Error object">
<cfdump var="#cgi#" label="CGI scope">
</cfmail>
<cfoutput>
<html><head><title>An error occurred.</title>
</head>
<body>
<div style="background-color: ##cc4400; padding: 1em;
<h3 style="color: black;">Sorry, there was an error. Site
admins have been contacted.</h3>
</div>
</body>
</html></cfoutput>
CFError example (cont’d)
• What user sees:
• What admin gets:
Application.cfc onError event (CF 7+)
• Arguments:
– Exception - exception object
• Similar in structure to the CFCatch object you get with cftry/cfcatch
– EventName - string
• Contains Application event name, if error is in Application.cfc
• Otherwise, blank string
• No return value
• You can/should still have a cferror tag in the declarations
section of your Application.cfc; that will run if there is an
error in your OnError event.
• Overrides all other error handlers besides CFCatch
• Check limitations in LiveDocs; no output if runs in
onApplicationEnd or onSessionEnd events
Application.cfc onError event Example
<cffunction name="onError" returnType="void" output="true">
<cfargument name="Exception" required="true"/>
<cfargument name="EventName" type="String" required="true" />
<cfoutput>Error caught in Application.cfc,
#GetCurrentTemplatePath()# <br/></cfoutput>
<cfoutput>Event name: '#Arguments.EventName#'</br></cfoutput>
<!--- <cfdump var="#Arguments#" label="Arguments">--->
<cfdump var="#Arguments.Exception#"
label="#Arguments.EventName# Exception">
<cfdump var="#CGI#" label="CGI">
<cfdump var="#variables#" label="variables in
application.cfc">
…
</cffunction>
Application.cfc onMissingTemplate
event (CF 8, beta)
• Used as a local application-specific 404
handler: when page specified in URL does
not exist.
• Arguments: targetPage string.
• Return true if handled ok, false if you want
to throw a 404 error.
– If there is a Missing Template error handler
defined in CFAdmin, that will catch.
– If that is not defined, CF's built-in default 404
handler will run
Application.cfc onMissingTemplate
event (CF 8, beta) example
<cffunction name="onMissingTemplate">
<cfargument name="targetPage" type="string" required=true/>
<!--- Use a try block to catch errors. --->
<cftry>
<!--- Log all errors. --->
<cflog type="error" text="Missing template:
#Arguments.targetPage#">
<!--- Display an error message. --->
<cfoutput>
<h3>#Arguments.targetPage# could not be found.</h2>
<p>You requested a non-existent ColdFusion page.<br />
Please check the URL.</p>
</cfoutput>
<cfreturn true />
<!--- If an error occurs, return false. --->
<cfcatch>
<cfreturn false />
</cfcatch>
</cftry>
</cffunction>
CFTry/CFCatch
• Wrap the CFTry/CFCatch around a block of
code, and it handles errors inside that block
• Handles errors locally; can show inside the
layout.
• Inside the cfcatch tags, you have an object
named “cfcatch”, contains error properties and
related objects.
• You can specify catching certain types only
• Rethrow error (tag CFRETHROW) if you want to
send the error to a higher level.
CFTry/CFCatch sample
<cferror type="exception" template="exception.cfm">
<!--- any code out here will be handled by the above exception handler "exception.cfm",
or by the Application.cfc OnError if it exists --->
<cfinclude template="test1.cfm">
<cftry>
<!--- Any code in here will be handled by these cfcatch blocks --->
<cfinclude template="test2.cfm"
<cfcatch type="Any">
<!--- Handle the error here --->
<h3>There was an error with this operation!</h3>
<cfdump var="#cfcatch#“ label="CFCatch object!">
</cfcatch>
</cftry>
<!--- any code out here will be handled by the above exception handler "exception.cfm",
or by the Application.cfc OnError if it exists --->
<cfinclude template="test3.cfm"
What to do in your error handler
• Log
– CF already logs basic exception info to exception.log
– Could log extra error info to file, one line per error
– New in CF8: there will be built-in Derby databases – all inside the CF
service, no connections to go down. This may allow for logging other
properties than would be doable in a text log, then provide for easy
search capability.
• Email
– HTML formatted email, get a table of all the info you need
• Use a common template
– Pass in settings for CFMail or logging.
– Optionally show debug info for local developers – pass in Debug
variable controlled by IP and a URL var
• CAUTION: if there is an error in this level, like DB connection, or
email malformed, will throw the original error to a higher level!
– You won't know about the exception in the error handler.
What to send
• Scopes: error/cfcatch/exception object, cgi
scope, form, other scopes
• Simple version: cfdump
• Server-wide handler: shouldn’t have a lot of
moving parts.
– If you check specific optional parts of the
error/catch object, check StructKeyExists first!
– If you have a more involved template, use
try/catch in that, and do a basic action by default.
Always handle.
CFDump
• You may want to write code to parse out the
properties of the error/catch object, instead of
just dumping.
– Highlight most important/useful properties at the top
of the email
– Potential issue with dumping a CFCatch: There may
be an issue with dumping the full object, depending
on server installation, version (6.1)
– Error detail message may not be clear; also could
include HTML content which you won’t want in there.
– Process SQL output, show query more visibly.
Example 1: CFError included in same
file
• err1.cfm :
<cferror type="exception" template="exception.cfm">
<h1>Example 1: Use cferror in the template</h1>
<!--- Undefined variable, will cause an error --->
<cfoutput>#NonExistentVariable#</cfoutput>
<h3>Since we are using cferror type="Exception",
html after the error will not appear,
and html before the error will only show in
Error.GeneratedContent.</h3>
Example 1 (cont’d)
• exception.cfm :
<!--- We should be mailing these details (like previous
CFError example), and showing only a nice message. --->
<h1>Exception Template Example 1</h1>
<h3>Error scope:</h3>
<cfdump var="#error#" >
<h3>CGI scope:</h3>
<cfdump var="#cgi#">
<h4>Error handled at:
<cfoutput>#GetCurrentTemplatePath()#</cfoutput>
</h4>
Example 2: CFError included in
Application.cfm
• Application.cfm
<cfsilent>
<cferror type="exception" template="exception.cfm">
</cfsilent>
• err2.cfm
<h1>Example 2: Use cferror in the Application.cfm</h1>
<!--- Undefined variable, will cause an error --->
<cfoutput>#NonExistentVariable#</cfoutput>
<h3>Since we are using cferror type="Exception",
html after the error will not appear,
and html before the error will only show in
Error.GeneratedContent.
</h3>
Example 2 (cont’d)
• exception.cfm
<!--- We should be mailing these details (like
previous CFError example), and showing only a nice
message. --->
<h1>Exception Template Example 2</h1>
<div style="background-color: #bbbbbb; padding: 2em;">
<h3>Error scope:</h3>
<cfdump var="#error#" >
<h3>CGI scope:</h3>
<cfdump var="#cgi#">
<h4>Error handled at:
<cfoutput>#GetCurrentTemplatePath()#</cfoutput>
</h4>
</div>
Example 3: onError event of
Application.cfc (CF7+ only)
• Application.cfc
<cfcomponent name="Application">
<cfset this.name="DLTestFolder">
<cferror type="exception" template="exception.cfm" >
<cffunction name="onError" returnType="void" output="true">
<cfargument name="Exception" required="true“ />
<cfargument name="EventName" type="String" required="true"/>
<cfoutput>Error caught in Application.cfc,
#GetCurrentTemplatePath()# <br/></cfoutput>
<cfoutput>Event name: '#Arguments.EventName#'</cfoutput>
<cfdump var="#Arguments.Exception#"
label="#Arguments.EventName# Exception">
<cfdump var="#CGI#" label="CGI">
</cffunction>
</cfcomponent>
Example 3 (cont’d)
• err3.cfm
<h1>Example 3: Use OnError in the Application.cfc</h1>
<!--- Undefined variable, will cause an error --->
<cfoutput>#NonExistentVariable#</cfoutput>
<h3>Since this error is caught by
its Application.cfc OnError event,
html after the error will not appear,
BUT html before the error will output to the browser.
</h3>
Example 4: onMissingTemplate event
of Application.cfc (CF8 only, in beta)
• Application.cfc
<cfcomponent name="Application">
<cfset this.name="DLTestFolder">
<cffunction name="onMissingTemplate">
<cfargument name="targetPage" type="string" required="true"/>
<!--- Use a try block to catch errors. --->
<cftry>
<!--- Log all errors. --->
<cflog type="error" text="Missing template: #Arguments.targetPage#">
<!--- Display an error message. --->
<cfoutput>
<h3>#Arguments.targetPage# could not be found.</h2>
<p>You requested a non-existent ColdFusion page.<br />
Please check the URL.</p>
</cfoutput>
<cfreturn true />
<!--- If an error occurs, return false and the default 404 error handler will run.
--->
<cfcatch>
<cfreturn false />
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
Example 5a, CFTry/CFCatch File error
• Application.cfc, like in example 3
• badfile.cfm
<h1>Example 5: Try/catch, file error</h1>
<!--- Wrap the bad code in try/catch --->
<cftry>
<!--- Code that causes the error --->
<cfinclude template="boogabooga.cfm">
<cfcatch type="any">
<!--- If you want to not handle this here,
rethrow this error to the higher handler. --->
<!--- <cfrethrow > --->
<cfdump var="#cfcatch#" label="CFCatch in Example 5">
<h4>Error handled at: <cfoutput>#GetCurrentTemplatePath()#, CFCatch</cfoutput></h4>
</cfcatch>
</cftry>
<h3>If there was no error in the Catch block, this should display.</h3>
Example 5b, CFTry/CFCatch DB error
• Application.cfc like in example 3
• baddb.cfm
<h1>Example 5: Try/catch - Database error</h1>
<!--- Wrap the bad code in try/catch --->
<cftry>
<!--- Code that causes the error; nonexistent table --->
<cfquery name="myquery" datasource="cfdocexamples“ >
Select bar FROM foo
</cfquery>
<cfcatch type="any">
<!--- If you want to not handle this here,
rethrow this error to the higher handler. --->
<!--- <cfrethrow > --->
<cfdump var="#cfcatch#" label="CFCatch in Example 5">
<h4>Error handled at: <cfoutput>#GetCurrentTemplatePath()#, CFCatch</cfoutput></h4>
</cfcatch>
</cftry>
<h3>If there was no error in the Catch block, this should display.</h3>
Example: CFError, break CFMail
• Exception.cfm (like the first CFError example)
. . . .
<cfmail serRRRver=“mailserver.domain.com"
from="[email protected]" to="#mailto#"
subject="Error in Example App on #CGI.HTTP_HOST#"
type="html">
. . . . .
• User sees original error:
Other useful info
• GetCurrentTemplatePath() – if you have
error handling templates multiple places,
shows exactly where this error template is.
• CGI. HTTP_HOST – Which site this is
running on (in subject line)
• Other CGI info
Caveats
• If you have a high-volume site, you may want
another solution than emailing you every
time, especially for errors that each and every
visitor will hit.
• If you use CFParam and CFQueryParam on
form or URL values: Make sure you handle
form validation before this on the server-side.
– Provides for nicer validation messages
– Form value type errors won’t clutter your inbox,
distracting from real errors.
References
•
Livedocs
– “Handling Errors” (chapter)
http://livedocs.adobe.com/coldfusion/7/htmldocs/00001130.htm
– “How ColdFusion handles errors”
http://livedocs.adobe.com/coldfusion/7/htmldocs/00001135.htm
– CFAdministrator Settings page: global 404 and exception handlers
http://livedocs.adobe.com/coldfusion/7/htmldocs/00001705.htm
– Application.cfc OnError
http://livedocs.adobe.com/coldfusion/7/htmldocs/00000697.htm
•
Quickdocs:
– http://cfquickdocs.com/cferror
– http://cfquickdocs.com/cftry
•
Other presos
– Mosh Teitelbaum, Feb 2004:
http://mdcfug.org/meetings/AdvancedColdFusionError_Handling.ppt
•
Google search
– “site:livedocs.adobe.com ColdFusion 7 keywords”