Tornado 莫名其妙的抛出“AssertionError” 异常,怎么办?

前几天我的Tornado每天都会产生几十KB的错误日志,这让我十分不解。因为错误的Trackback基本上都是

assert not self._finished
AssertionError
ERROR:root:Cannot send error response after headers written

虽然错误时有发生,不过程序运行起来倒是一切正常,直到有一天,我写了一个不足20行的程序时,错误再次发生,这显然是找出原因的绝佳时机。当然,最后的真正原因的确让人大跌眼镜。

先看一段示例代码,这段代码可以很好的重现上面错误的产生过程(由于Wordpress抓狂的排版系统,缩进什么的请忽略):

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.finish()
        self.write(“Hello, world”)

        application = tornado.web.Application([
            (r"/", MainHandler),
        ])

    if __name__ == “__main__”:
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start() 

看起来没问题?是的,但是当你打开“http://127.0.0.1:8080/”时,错误就发生了。

仔细观察Trackback,这一次错误出现在self.write()这一句,那么说明什么?

说明我们执行self.finish()以后,MainHandler里面的处理函数继续向下执行了。

我对这种逻辑处理方式不能理解,self.finish()执行后,理应终止函数执行,那么为什么Tornado不这么做呢?我在知乎上提出了这个问题,得到了两位知乎攻城师的耐心解答,在此引用一下:

@安江泽
self.finish()代表回应生成的终结,并不代表着请求处理逻辑的终结。假设你有一个block的逻辑是和回应无关的,那么放在self.finish()的后面可以显著的缩短响应时间。

所以,如果你确定自己的逻辑需要立即返回,可以在self.finish()后立刻return。Tornado在将这个自由留给了你自己。

另外一个理由是,在call stack里让顶端的函数去弹出一个非顶端的函数,这个逻辑有点奇怪。唯一能够提供退出的机制就是异常了。但是在正常逻辑里面使用异常去实现一个功能,也是很怪的逻辑。

@杨昆
没错  同理还有self.render/self.write
我们在所有这种response语句前加return 例如  return self.redirect(‘/’)

至此,这个问题得到了完美的解决和解答,而我想后者才是更重要的。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。