Appengine: Custom Error Handlers using webapp2 - Python 2.7
Google Developers has a writeup on Custom Error Responses using app.yaml
Here is a sample app.yaml
app.yaml
On Appengine, a standard 404 Error is shown
articles.py
Let us use the advice on this Google Developers page under Custom Error Responses section
The page further goes on to say, that error_code can be
1. over_quota
2. dos_api_denial
3. timeout
Whether this error_handler can handle 404 or 500 errors is not mentioned.
The error_code part is optional. So we edit app.yaml as follows app.yaml
app.yaml
On testing on both the development server and live environments, the Custom error page, default_error.html is not served for 404 errors. We get the same 404 error as before.
I could not come up with something that would raise a 500 error without having to use a script.
Additionally, I read this comment on this Google Code page
articles.py
On visiting /articles/ on the dev_server, I do not get an error. But the live environment gives me the custom error page.
The Developer page says
However, it does not work for 404 errors and I have my doubts about 500 errors being handled.
On the other hand, 500 errors, will most likely be encountered in scripts, and there is a simpler way to handle 404, 500 and other exceptions within a script.
The example below is for webapp2. I haven't tried the same on webapp.
Error handling using handle_exception():
http://webapp-improved.appspot.com/guide/exceptions.html describes the handle_exception method
handle_exception is a method of webapp2.RequestHandler. Any uncaught exceptions are passed on to this method. All this method does by default is raise the error to WSGIApplication.handle_exception().
To use it, we extend webapp2.RequestHandler.
articles.py is edited as follows
(code adapted from webapp-improved.appspot.com/guide/exceptions.html)
articles.py
On visiting /articles/ I get a 500 error, with our custom text "Custom Error Message"
On visiting /articles/blah ,which I am not mapping to anything, I get a generic 404 error. This is because, all that the articles module is used for is the url /articles/ and nothing else.
Changed articles.py as follows
articles.py
(code from http://code.google.com/codesearch#Qx8E-7HUBTk/trunk/python/lib/webapp2/webapp2.py Apache2 License)
How to handle errors out of url path /articles/.* ?
Map everything else to a script, which does the error handling as done in articles.py
app.yaml
others.py
tl;dr :
Custom Error Handling in appengine:
1. over_quota
2. dos_api_denial
3. timeout
for the above three use, error handler in app.yaml
For 404, 500 and other errors in appengine:
extend webapp2.RequestHandler
override handle_exception() method and set your own custom message.
I haven't described template usage to keep things simple for myself. Additionally, you should go through http://webapp-improved.appspot.com/guide/exceptions.html. I have skipped the logging part of handling exceptions, which you might want to include.
Sources:
Google Developers - https://developers.google.com/appengine/docs/python/config/appconfig#Custom_Error_Responses
Webapp2 Docs - webapp-improved.appspot.com/guide/exceptions.html
Google Code Search - License Apache 2 - http://code.google.com/codesearch#Qx8E-7HUBTk/trunk/python/lib/webapp2/webapp2.py
Here is a sample app.yaml
app.yaml
application: appname version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: /static static_dir: static http_headers: Vary: Accept-Encoding - url: /articles/.* script: articles.appOn the Development Environment, I get the following error when I visit http://localhost:8080/ i.e the home page
Not found error: / did not match any patterns in application configuration.
On Appengine, a standard 404 Error is shown
Error: Not Found The requested URL / was not found on this server.This is because the app.yaml file does not specify any handler for "/" Here is the articles.py file
articles.py
import webapp2 class HomePage(webapp2.RequestHandler): def get(self): self.response.write.out("Hello Birds!") app = webapp2.WSGIApplication( [ (r'/articles/', HomePage) ], debug=True)Specifying Custom Error Pages in app.yaml
Let us use the advice on this Google Developers page under Custom Error Responses section
error_handlers: - file: default_error.html - error_code: over_quota file: over_quota.html
The page further goes on to say, that error_code can be
1. over_quota
2. dos_api_denial
3. timeout
Whether this error_handler can handle 404 or 500 errors is not mentioned.
The error_code part is optional. So we edit app.yaml as follows app.yaml
app.yaml
application: appname version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: /static static_dir: static http_headers: Vary: Accept-Encoding - url: /articles/.* script: articles.app error_handlers: - file: default_error.html
On testing on both the development server and live environments, the Custom error page, default_error.html is not served for 404 errors. We get the same 404 error as before.
I could not come up with something that would raise a 500 error without having to use a script.
Additionally, I read this comment on this Google Code page
"Over quota error pages are only displayed if your entire app is over quota (eg, out of instance hours or bandwidth). If you've run out of quota for a specific API, then an exception is thrown..."Out of the three error codes supported, timeout is one which we can try to reproduce. Any request that takes more than 30 seconds will produce a timeout error. Change articles.py to the following
articles.py
import webapp2,time class HomePage(webapp2.RequestHandler): def get(self): time.sleep(140) self.response.write("Hello Birds!") app = webapp2.WSGIApplication( [ (r'/articles/', HomePage) ], debug=True)The script sleeps for 140 seconds, enough to produce a timeout.
On visiting /articles/ on the dev_server, I do not get an error. But the live environment gives me the custom error page.
The Developer page says
"Warning!: Make sure that the path to the error response file does not overlap with static file handler paths. "But editing app.yaml, and moving the custom error file to a static directory, still gives me the custom error page on the live environment.
error_handlers: - file: static/default_error.htmlNote that I have only checked this for timeout. It hopefully should work for dos_api_denial and over_quota too.
However, it does not work for 404 errors and I have my doubts about 500 errors being handled.
On the other hand, 500 errors, will most likely be encountered in scripts, and there is a simpler way to handle 404, 500 and other exceptions within a script.
The example below is for webapp2. I haven't tried the same on webapp.
Error handling using handle_exception():
http://webapp-improved.appspot.com/guide/exceptions.html describes the handle_exception method
handle_exception is a method of webapp2.RequestHandler. Any uncaught exceptions are passed on to this method. All this method does by default is raise the error to WSGIApplication.handle_exception().
To use it, we extend webapp2.RequestHandler.
articles.py is edited as follows
(code adapted from webapp-improved.appspot.com/guide/exceptions.html)
articles.py
import webapp2 class BaseHandler(webapp2.RequestHandler): def handle_exception(self, exception, debug): # Set a custom message. self.response.write('Custom Error Message') # If the exception is a HTTPException, use its error code. # Otherwise use a generic 500 error code. if isinstance(exception, webapp2.HTTPException): self.response.set_status(exception.code) else: self.response.set_status(500) class HomePage(BaseHandler): def get(self): self.session.pop("h") self.response.write("Hello Birds!") app = webapp2.WSGIApplication( [ (r'/articles/', HomePage) ], debug=True)In the HomePage class, I am trying to pop a session when I have no session defined, so that a 500 error is raised.
On visiting /articles/ I get a 500 error, with our custom text "Custom Error Message"
On visiting /articles/blah ,which I am not mapping to anything, I get a generic 404 error. This is because, all that the articles module is used for is the url /articles/ and nothing else.
Changed articles.py as follows
articles.py
import webapp2 class BaseHandler(webapp2.RequestHandler): def handle_exception(self, exception, debug): # Set a custom message. self.response.write('An error occurred.') # If the exception is a HTTPException, use its error code. # Otherwise use a generic 500 error code. if isinstance(exception, webapp2.HTTPException): self.response.set_status(exception.code) else: self.response.set_status(500) class MissingPage(BaseHandler): def get(self): self.response.set_status(404) self.response.write("404 Custom Error!") class HomePage(BaseHandler): def get(self): self.response.write("Hello Birds!") app = webapp2.WSGIApplication( [ (r'/articles/', HomePage), (r'/articles/.*', MissingPage) ], debug=True)Now, when I visit /articles/blah I get my 404 Custom error message. Instead of self.response.set_status, you can use self.error as well
class MissingPage(BaseHandler): def get(self): self.error(404) self.response.write("404 Custom Error!")error in self.error is a method of webapp2.RequestHandler, which does the following
(code from http://code.google.com/codesearch#Qx8E-7HUBTk/trunk/python/lib/webapp2/webapp2.py Apache2 License)
self.response.status = HTTP_ERROR_CODE self.response.clear()
How to handle errors out of url path /articles/.* ?
Map everything else to a script, which does the error handling as done in articles.py
app.yaml
application: appname version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: /static static_dir: static http_headers: Vary: Accept-Encoding - url: /articles/.* script: articles.app - url: /.* script: others.app error_handlers: - file: error.html
others.py
import webapp2 class BaseHandler(webapp2.RequestHandler): def handle_exception(self, exception, debug): self.response.write('An error occurred.') if isinstance(exception, webapp2.HTTPException): self.response.set_status(exception.code) else: self.response.set_status(500) class MissingPage(BaseHandler): def get(self): self.response.set_status(404) self.response.write("404 Custom!") app = webapp2.WSGIApplication( [ (r'/.*', MissingPage) ], debug=True)This will map everything other than /articles/ and your static files as mentioned in app.yaml to our custom error page.
tl;dr :
Custom Error Handling in appengine:
1. over_quota
2. dos_api_denial
3. timeout
for the above three use, error handler in app.yaml
error_handlers: - file: default_error.html - error_code: over_quota file: over_quota.html
For 404, 500 and other errors in appengine:
extend webapp2.RequestHandler
override handle_exception() method and set your own custom message.
I haven't described template usage to keep things simple for myself. Additionally, you should go through http://webapp-improved.appspot.com/guide/exceptions.html. I have skipped the logging part of handling exceptions, which you might want to include.
Sources:
Google Developers - https://developers.google.com/appengine/docs/python/config/appconfig#Custom_Error_Responses
Webapp2 Docs - webapp-improved.appspot.com/guide/exceptions.html
Google Code Search - License Apache 2 - http://code.google.com/codesearch#Qx8E-7HUBTk/trunk/python/lib/webapp2/webapp2.py
Comments
Post a Comment