How to catch all exceptions with CherryPy?

社会主义新天地 提交于 2019-12-07 06:22:44

问题


I use CherryPy to run a very simple web server. It is intended to process the GET parameters and, if they are correct, do something with them.

import cherrypy

class MainServer(object):
    def index(self, **params):
        # do things with correct parameters
        if 'a' in params:
            print params['a']

    index.exposed = True

cherrypy.quickstart(MainServer())

For example,

http://127.0.0.1:8080/abcde:

 404 Not Found

The path '/abcde' was not found.

Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\cherrypy\_cprequest.py", line 656, in respond
    response.body = self.handler()
  File "C:\Python27\lib\site-packages\cherrypy\lib\encoding.py", line 188, in __call__
    self.body = self.oldhandler(*args, **kwargs)
  File "C:\Python27\lib\site-packages\cherrypy\_cperror.py", line 386, in __call__
    raise self
NotFound: (404, "The path '/abcde' was not found.")
Powered by CherryPy 3.2.4

I am trying to catch this exception and show a blank page because the clients do not care about it. Specifically, the result would be an empty body, no matter the url or query string that resulted in an exception.

I had a look at documentation on error handling cherrypy._cperror, but I did not find a way to actually use it.

EDIT: I gave up using CherryPy and found a simple solution using BaseHTTPServer (see my answer below, downvoted because it solves the issue but does not answer the question ...sigh...)


回答1:


Docs somehow seem to miss this section. This is what I found while looking for detailed explanation for custom error handling from the source code.

Custom Error Handling

Anticipated HTTP responses

The 'error_page' config namespace can be used to provide custom HTML output for expected responses (like 404 Not Found). Supply a filename from which the output will be read. The contents will be interpolated with the values %(status)s, %(message)s, %(traceback)s, and %(version)s using plain old Python string formatting.

_cp_config = {
    'error_page.404': os.path.join(localDir, "static/index.html")
}

Beginning in version 3.1, you may also provide a function or other callable as an error_page entry. It will be passed the same status, message, traceback and version arguments that are interpolated into templates

def error_page_402(status, message, traceback, version):
    return "Error %s - Well, I'm very sorry but you haven't paid!" % status
cherrypy.config.update({'error_page.402': error_page_402})

Also in 3.1, in addition to the numbered error codes, you may also supply error_page.default to handle all codes which do not have their own error_page entry.

Unanticipated errors

CherryPy also has a generic error handling mechanism: whenever an unanticipated error occurs in your code, it will call Request.error_response to set the response status, headers, and body. By default, this is the same output as HTTPError(500). If you want to provide some other behavior, you generally replace "request.error_response".

Here is some sample code that shows how to display a custom error message and send an e-mail containing the error

from cherrypy import _cperror

def handle_error():
    cherrypy.response.status = 500
    cherrypy.response.body = [
        "<html><body>Sorry, an error occurred</body></html>"
    ]
    sendMail('error@domain.com',
             'Error in your web app',
             _cperror.format_exc())

@cherrypy.config(**{'request.error_response': handle_error})
class Root:
    pass

Note that you have to explicitly set response.body and not simply return an error message as a result.




回答2:


Choose what's most suitable for you: Default Methods, Custom Error Handling.

I don't think you should use BaseHTTPServer. If your app is that simple, just get a lightweight framework (e. g. Flask), even though it might be a bit overkill, OR stay low level but still within the WSGI standard and use a WSGI-compliant server.




回答3:


CherryPy IS catching your exception. That's how it returns a valid page to the browser with the caught exception.

I suggest you read through all the documentation. I realize it isn't the best documentation or organized well, but if you at least skim through it the framework will make more sense. It is a small framework, but does almost everything you'd expect from a application server.

import cherrypy


def show_blank_page_on_error():
    """Instead of showing something useful to developers but
    disturbing to clients we will show a blank page.

    """
    cherrypy.response.status = 500

    cherrypy.response.body = ''


class Root():
    """Root of the application"""

    _cp_config = {'request.error_response': show_blank_page_on_error}

    @cherrypy.expose
    def index(self):
        """Root url handler"""

        raise Exception 

See this for the example in the documentation on the page mentioned above for further reference.




回答4:


You can simply use a try/except clause:

try:
    cherrypy.quickstart(MainServer())
except: #catches all errors, including basic python errors
    print("Error!")

This will catch every single error. But if you want to catch only cherrypy._cperror:

from cherrypy import _cperror

try:
    cherrypy.quickstart(MainServer())
except _cperror.CherryPyException: #catches only CherryPy errors.
    print("CherryPy error!")

Hope this helps!




回答5:


Though this was the one of the top results when I searched for cherrypy exception handling, accepted answer did not fully answered the question. Following is a working code against cherrypy 14.0.0

# Implement handler method
def exception_handler(status, message, traceback, version)
    # Your logic goes here 

class MyClass()    

   # Update configurations
   _cp_config = {"error_page.default": exception_handler}

Note the method signature. Without this signature your method will not get invoked.Following are the contents of method parameters,

  • status : HTTP status and a description
  • message : Message attached to the exception
  • traceback : Formatted stack trace
  • version : Cherrypy version



回答6:


Maybe you could use a 'before_error_response' handler from cherrypy.tools

@cherrypy.tools.register('before_error_response', priority=90)
def handleexception():
    cherrypy.response.status = 500
    cherrypy.response.body = ''

And don't forget to enable it:

tools.handleexception.on = True



回答7:


I gave up using CherryPy and ended up using the follwing code, which solves the issue in a few lines with the standard BaseHTTPServer:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from urlparse import urlparse, parse_qs

class GetHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        url = urlparse(self.path)
        d = parse_qs(url[4])
        if 'c' in d:
            print d['c'][0]
        self.send_response(200)
        self.end_headers()
        return

server = HTTPServer(('localhost', 8080), GetHandler)
server.serve_forever()


来源:https://stackoverflow.com/questions/20395565/how-to-catch-all-exceptions-with-cherrypy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!