V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Tornado Documentation
http://www.v2ex.com/tornado/
Tornado on GitHub
https://github.com/facebook/tornado/
Tornado Gists
http://tornadogists.org/
mgna17
V2EX  ›  Tornado

问一个关于 tornado 异常处理的新手问题

  •  1
     
  •   mgna17 · 2016-06-05 17:07:42 +08:00 · 12773 次点击
    这是一个创建于 3121 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚开始学 tornado ,它的异常处理机制有点弄不明白。

    写了一个测试用的小脚本,期望遇到 404 的时候能够触发我自己声明的 write_error 函数,然而 write_error 并没有生效,输出的是 tornado 默认的 404 页面。

    代码如下:

    #!/bin/env python3.5
    #coding:utf-8
    import os
    
    import tornado.httpserver
    import tornado.ioloop
    import tornado.options
    import tornado.web
    
    from tornado.options import define, options
    
    define("port", default=8000, help="端口", type=int)
    
    class BaseHandler(tornado.web.RequestHandler):
        def write_error(self, stat, **kw):
            self.write('Func write_error !')
    
    
    class IndexHandler(BaseHandler):
        def get(self):
            self.write('hello')
    
    handlers = [ 
        (r'/index', IndexHandler),
        ]   
    
    settings = { 
            'template_path': os.path.join(os.path.dirname(__file__), "templates"),
            'static_path': os.path.join(os.path.dirname(__file__), 'static'),
            }
    
    if __name__ == '__main__':
            tornado.options.parse_command_line()
            app = tornado.web.Application(handlers=handlers, **settings)
            http_server = tornado.httpserver.HTTPServer(app)
            http_server.listen(options.port)
            print(options.port)
            tornado.ioloop.IOLoop.instance().start()
    

    然后去 google 了一下,把 BaseHandler 成了这样,但是 404 的时候还是返回了默认的 404 页面:

    class BaseHandler(tornado.web.RequestHandler):
        def _handle_request_exception(self, e):
            self.write_error(404)
    
        def send_error(self, stat, **kw):
            self.write_error(404)
    
        def write_error(self, stat, **kw):
            self.write('Func write_error !')
    
    7 条回复    2016-08-13 00:36:06 +08:00
    shuax
        1
    shuax  
       2016-06-05 18:22:32 +08:00
    tornado.web.RequestHandler.write_error = write_error

    我是这样写的
    lianghui
        2
    lianghui  
       2016-06-05 18:26:44 +08:00
    ```python

    class NotFondHandler(BaseHandler):

    def get(self):
    self.write("This page ``{}``is not Found".format(self.request.path))


    settings = {
    'template_path': os.path.join(os.path.dirname(__file__), "templates"),
    'static_path': os.path.join(os.path.dirname(__file__), 'static'),
    'default_handler_class': NotFondHandler
    }

    default_handler_class and default_handler_args: This handler will be used if no other match is found; use this to implement custom 404 pages (new in Tornado 3.2).

    ```
    mgna17
        3
    mgna17  
    OP
       2016-06-05 18:40:09 +08:00 via Android
    @shuax 这样写结果上和我的继承覆盖写法没差别吧 😓
    mgna17
        4
    mgna17  
    OP
       2016-06-05 18:42:34 +08:00 via Android
    @lianghui 谢谢你的回答,这是一个优雅的解决方案,但是,实际上我想知道的是:为什么我写的是错的
    lianghui
        5
    lianghui  
       2016-06-05 19:01:34 +08:00   ❤️ 2
    @mgna17 因为 RequestDispatcher 在没有找到 handler 默认设置将 handler 为 ErrorHandler,如果指定了 default_handler_class ,就使用 default_handler_class 。

    ErrorHandler 继承了 RequestHandler , 所以 hook RequestHandler.write_error 有效。 详细看 tornado.web._RequestDispatcher route 处理实现
    mgna17
        6
    mgna17  
    OP
       2016-06-05 20:09:39 +08:00
    @lianghui 非常感谢,我的问题解决了
    lenbias34
        7
    lenbias34  
       2016-08-13 00:36:06 +08:00
    说白了 404 错误就是路由不匹配,
    我们看 tornado 源码文件 web.py 中有 Application 类中的__call__方法中有:
    if not handler:
    handler = ErrorHandler(self, request, status_code=404)
    也就是所有错误的路由( 404 )将统一由 ErrorHandler 来处理, 再看看 ErrorHandler 的源码定义:
    class ErrorHandler(RequestHandler):
    """Generates an error response with status_code for all requests."""
    def initialize(self, status_code):
    self.set_status(status_code)

    def prepare(self):
    raise HTTPError(self._status_code)

    可以看到 ErrorHandler 继承自 RequestHandler 而并非你自定义的 BaseHandler 类
    所以即使你在 BaseHandler 中定义了 write_error 方法, ErrorHandler 中也不会有 write_error 的处理逻辑

    PS :自定义的 write_error 逻辑将在请求路由存在, 但请求方法错误时被调用
    比如,就拿你的代码来说: 如果你向 '/' 发出 POST 请求( curl -X POST http://localhost:8000/ ),就会返回 Func write_error !错误
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2570 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 18ms · UTC 06:38 · PVG 14:38 · LAX 22:38 · JFK 01:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.