Introduction
When an application returns a status code other than 200, which is the code for "everything went fine", you might wish to display a message to the user explaining what happened with an error document.
Pylons provides a facility for displaying customized error messages to users via the ErrorDocuments middleware. For those familiar with Apache's ErrorDocument directive, Pylons' ErrorDocuments provides similar functionality.
If an error document is not provided by an application, users will see the browser's default page for that error, or a blank screen, depending on their browser.
The Default Setup
Newly created Pylons applications come configured with the ErrorDocuments middleware enabled. The middleware is setup to call Pylons error_mapper function; which in turn calls the application's ErrorController. The ErrorController renders the actual error document shown to the user; it uses Pylons' error_document_template HTML by default.
Every part of the error documents system can be configured and customized to provide whatever error handling you like.
Disabling Error Documents Support
To disable error documents, just remove the following lines from your config/middleware.py file:
1 2 3 | # Display error documents for 401, 403, 404 status codes (if debug is disabled also # intercepts 500) app = ErrorDocuments(app, global_conf, mapper=error_mapper, **app_conf) |
Any status codes will no longer be intercepted.
Changing the template
To use a different template for the error documents, modify your ErrorController (in controllers/error.py). Change the document() action so that rather than using the pylons.middleware.error_document_template HTML string as a template, it uses your own template:
1 2 3 4 5 6 7 8 9 10 11 | def document(self): my_template=""" <html> <head><title>Error %(code)s</title></head> <body> <h1>Error %(code)s</h1> <p>%(message)s</p> </body> </html> """ % {'code':request.GET('code', ''), 'message':request.GET('message', '')} return my_template |
The other actions in the default ErrorController are most likely unnecessary when using a customized template. They serve images and style sheets from the Pylons package, for use by Pylons' error_document_template, without the need for those files to be located in your application's public directory.
Changing the error mapper
By default the status codes 404, 500, 401 and 403 are intercepted and redirected to the error controller. This is done by the error mapper specified in the error documents middleware. Have a look at your config/middleware.py file:
1 2 3 | # Display error documents for 401, 403, 404 status codes (if debug is disabled also # intercepts 500) app = ErrorDocuments(app, global_conf, mapper=error_mapper, **app_conf) |
By default the pylons.middleware.error_mapper is used. It looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from urllib import urlencode from paste.deploy.converters import asbool def error_mapper(code, message, environ, global_conf=None, **kw): if environ.get('pylons.error_call'): return None else: environ['pylons.error_call'] = True if global_conf is None: global_conf = {} codes = [401, 403, 404] if not asbool(global_conf.get('debug')): codes.append(500) if code in codes: # StatusBasedForward expects a relative URL (no SCRIPT_NAME) url = '/error/document/?%s' % (urllib.urlencode({'message': message, 'code': code})) return url |
Note how in debug mode the mapper does not intercept server error 500 codes as they are used for the error report produced by the PylonsEvalException middleware.
You can create your own error mapper based on this one to intercept different status codes by changing the line if code in [401, 403, 404, 500]. You can even change the URL so that a static file is served from your public directory rather than by the error controller. Just specify your error_mapper as the mapper parameter to middleware.
Testing Your Error Document
You can test your error document implementation by aborting a request with abort(). The method takes two parameters: the first is an integer representing the error code, the second is the response message to send as part of the status HTTP header.
Add a controller to your project named error_doc_test:
1 | $ paster controller error_doc_test
|
Modify your controller's index() action to look like this:
1 2 | def index(self): abort(500, 'Internal Server Error') |
Then start your server as described in the Getting Started Guide and visit http://localhost:5000/error_doc_test/
You should see the error 500 page with an Internal Server Error message.
Comments (1)
Jul 25, 2009
squiz says:
There is an error under 'Changing the template' on line 9 It says request.GET('...There is an error under 'Changing the template' on line 9
It says request.GET('code', ''), but it should really say request.GET.get('code', '')
The error is repeated twice