刚开始学 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 !')
![]() | 1 shuax 2016-06-05 18:22:32 +08:00 tornado.web.RequestHandler.write_error = write_error 我是这样写的 |
![]() | 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). ``` |
![]() | 4 mgna17 OP @lianghui 谢谢你的回答,这是一个优雅的解决方案,但是,实际上我想知道的是:为什么我写的是错的 |
![]() | &bsp; 5 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 处理实现 |
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 !错误 |