【问题标题】:How to catch all exceptions with CherryPy?如何用 CherryPy 捕获所有异常?
【发布时间】:2013-12-22 03:09:49
【问题描述】:

我使用CherryPy 来运行一个非常简单的网络服务器。它旨在处理GET 参数,如果它们正确,则对它们进行处理。

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())

例如,

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

我试图捕捉这个异常并显示一个空白页面,因为客户不关心它。具体来说,无论是导致异常的 url 或查询字符串,结果都将是一个空正文。

我查看了有关错误处理 cherrypy._cperror 的文档,但没有找到实际使用它的方法。

注意:我放弃了使用CherryPy,并找到了使用BaseHTTPServersee my answer below)的简单解决方案

【问题讨论】:

  • 为什么不使用try, except
  • @ZagorulkinDmitry:我试过了,但显然这不起作用(见我上面的更新)
  • 如果客户不关心,这是什么原因?你还想要 404 状态而只是没有内容吗?您关心的是追溯文本吗?
  • @jwalker:客户端发送了一个带有信息的查询,但这是一条单向消息。他们不期望任何回报(甚至没有代码 - 我可以随时发回200)。然后我使用他们在我的脚本中发送的内容。是的 - 我关心的是响应中的回溯文本(我想要一个空响应)。

标签: python exception cherrypy


【解决方案1】:

您可以简单地使用try/except 子句:

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

这将捕获每一个错误。但是如果你只想抓cherrypy._cperror:

from cherrypy import _cperror

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

希望这会有所帮助!

【讨论】:

  • 啊当然-我没想过把try, except放在那里。我更新了我的代码,但它不起作用(在尝试 http://127.0.0.1:8080/abcde 时,我得到一个 404 并且 Python 回溯指示一个 NotFoundexception)
  • 嗯.. 我认为这不应该发生。这是你的全部功能代码吗?
  • 我用包含您的解决方案的实际代码更新了我的问题。可以看到错误没有被捕获。
  • 不,当然还有更多代码(您可以在其中看到print params['a'])。但是我放的代码是功能齐全的,包括缺少异常捕获。你还需要什么?
  • 一个错误无法逃脱except 子句。请发布您的整个代码。
【解决方案2】:

CherryPy IS 捕捉到您的异常。这就是它向浏览器返回有效页面并捕获异常的方式。

我建议您通读所有文档。我意识到它不是最好的文档,也不是组织得很好,但如果你至少浏览一下它,这个框架会更有意义。它是一个小型框架,但几乎可以满足您对应用程序服务器的所有期望。

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 

请参阅this 以获取上述页面上文档中的示例以供进一步参考。

【讨论】:

  • 我查了谷歌,我确实看到了解决方案。我只是没能让它发挥作用。如果您知道如何解决问题,那么相关的代码会很棒。
  • @WoJ StackOverflow 社区并不是要向那些表现出明显缺乏努力和对主题的理解迹象的人提供讲义。不过,我觉得很慷慨。另外,您决定修改您的问题并回答您自己的新问题,我有点不安。现在,您已经接受了一个答案并评论了处理 GET 参数并找到合适的处理程序而不是捕获异常的解决方案。这就是为什么一次多个问题通常也是一个坏主意。您还在论坛中重复发布了您的问题...糟糕的形式。
  • 感谢您的慷慨,我很感激。首先:我最初问了一个完整的问题,其中包含代码和不起作用的示例。我应该怎么问?缺少什么研究? (指的是“明显缺乏努力”——你无法从屏幕后面判断,恕我直言)。第二:在您决定发布实际代码之前(这很好,不要误会我的意思),没有一个答案回答了我的问题。因此,在 更多研究 之后,我找到了一个不使用 CherryPy 的解决方案 - 并修改了我的问题 + 添加了一些有效的东西。 (接下来是……)
  • (上一部分的后续)。因此,既然我看到了完全解决问题的工作代码,我将更改最佳答案(尽管投反对票)。这就是所谓的“互相帮助”,这是 SO 这样的地方的核心。
  • 发布了非工作代码。如果您启动它,然后复制我在代码中添加的步骤,您会看到我的问题中描述的问题。您对问题被捕获并显示在浏览器中这一事实的评论很有用——这正是我想要避免的(显示回溯)
【解决方案3】:

我放弃了使用CherryPy 并最终使用了以下代码,它用标准的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()

【讨论】:

    【解决方案4】:

    选择最适合您的:Default MethodsCustom Error Handling

    我认为你不应该使用BaseHTTPServer。如果您的应用程序如此简单,只需获得一个轻量级框架(例如 Flask),即使它可能有点矫枉过正,或者保持低级但仍符合 WSGI 标准并使用符合 WSGI 标准的服务器。

    【讨论】:

      【解决方案5】:

      虽然这是我搜索cherrypy异常处理时的最佳结果之一,但接受的答案并没有完全回答这个问题。以下是针对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}
      

      注意方法签名。如果没有此签名,您的方法将不会被调用。以下是方法参数的内容,

      • 状态:HTTP 状态和说明
      • message:附加到异常的消息
      • traceback :格式化的堆栈跟踪
      • 版本 : Cherrypy 版本

      【讨论】:

        【解决方案6】:

        也许您可以使用来自 cherrypy.tools 的“before_error_response”处理程序

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

        别忘了启用它:

        tools.handleexception.on = True
        

        【讨论】:

          【解决方案7】:

          文档似乎以某种方式错过了这一部分。这是我在从源代码中寻找自定义错误处理的详细解释时发现的。

          自定义错误处理

          预期的 HTTP 响应

          “error_page”配置命名空间可用于提供自定义 HTML 输出 预期的响应(如 404 Not Found)。提供一个文件名, 将读取输出。内容将使用值进行插值 %(status)s、%(message)s、%(traceback)s 和 %(version)s 使用普通的旧 Python string formatting.

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

          从 3.1 版开始,您还可以提供一个函数或其他可调用对象 error_page 条目。它将被传递相同的状态、消息、回溯和 插入到模板中的版本参数

          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})
          

          同样在 3.1 中,除了编号的错误代码,您还可以提供 error_page.default 处理所有没有自己error_page的代码 进入。

          意外错误

          CherryPy 也有一个通用的错误处理机制: 您的代码中发生错误,它将调用 Request.error_response 到 设置响应状态、标头和正文。默认情况下,这是相同的 输出为 HTTPError(500)。如果您想提供 其他一些行为,你通常替换“request.error_response”。

          这里是一些示例代码,展示了如何显示自定义错误消息和 发送包含错误的电子邮件

          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
          

          请注意,您必须明确设置 response.body 而不是简单地返回错误消息。

          【讨论】:

          • 谢谢 - 我已经有几年没有使用 CherryPy 了,所以我相信你这是正确的 :)
          【解决方案8】:
          import cherrypy
          from cherrypy import HTTPError
          
          
          def handle_an_exception():
              cherrypy.response.status = 500
              cherrypy.response.headers['content-type'] = 'text/plain;charset=UTF-8'
              cherrypy.response.body = b'Internal Server Error'
          
          
          def handle_a_404(status=None, message=None, version=None, traceback=None):
              cherrypy.response.headers['content-type'] = 'text/plain;charset=UTF-8'
              return f'Error page for 404'.encode('UTF-8')
          
          
          def handle_default(status=None, message=None, version=None, traceback=None):
              cherrypy.response.headers['content-type'] = 'text/plain;charset=UTF-8'
              return f'Default error page: {status}'.encode('UTF-8')
          
          
          class Root:
              """Root of the application"""
              _cp_config = {
                  # handler for an unhandled exception
                  'request.error_response': handle_an_exception,
                  # specific handler for HTTP 404 error
                  'error_page.404': handle_a_404,
                  # default handler for any other HTTP error
                  'error_page.default': handle_default
              }
          
              @cherrypy.expose
              def index(self):
                  """Root url handler"""
                  raise Exception("an exception")
          
              @cherrypy.expose
              def simulate400(self):
                  raise HTTPError(status=400, message="Bad Things Happened")
          
          
          cherrypy.quickstart(Root())
          

          测试:

          http://127.0.0.1:8080/

          http://127.0.0.1:8080/simulate400

          http://127.0.0.1:8080/missing

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-07-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-01
            • 2011-11-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多