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

2016-06-05 17:07:42 +08:00
 mgna17

刚开始学 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 !')
12209 次点击
所在节点    Tornado
7 条回复
shuax
2016-06-05 18:22:32 +08:00
tornado.web.RequestHandler.write_error = write_error

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

ErrorHandler 继承了 RequestHandler , 所以 hook RequestHandler.write_error 有效。 详细看 tornado.web._RequestDispatcher route 处理实现
mgna17
2016-06-05 20:09:39 +08:00
@lianghui 非常感谢,我的问题解决了
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 !错误

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/283654

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX