為什麼 Tornado 在調用 self.finish() 以後不終止 RequestHandler 中相關處理函數的運行?

一個很簡單的程序:

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

如果我們訪問的話,Tornado會報錯,Trackback如下:

Traceback (most recent call last):

File "C:Python27libsite-packages ornadoweb.py", line 927, in _execute

getattr(self, self.request.method.lower())(*args, **kwargs)

File "I:party est.py", line 9, in get

self.write("Hello, world")

File "C:Python27libsite-packages ornadoweb.py", line 442, in write

assert not self._finished

AssertionError

ERROR:root:Cannot send error response after headers written

很顯然,在我們調用self.finish()以後,RequestHandler的處理函數繼續向下執行了,從而導致了錯誤的發生。

那麼,為什麼在調用self.finish()以後,Tornado不自動終止函數的執行呢?

另外,知乎對這種情況是怎麼處理的?我現在的做法是在self.redirect()以後加一句return,不知道合適不合適。

self.redirect內部同樣調用了self.finish,也會出現這樣的問題。而且對於用戶來說,執行self.redirect以後發送Location Header,用戶就被跳轉走了,繼續執行是沒有意義的。


self.finish()代表回應生成的終結,並不代表著請求處理邏輯的終結。假設你有一個block的邏輯是和回應無關的,那麼放在self.finish()的後面可以顯著的縮短響應時間。

所以,如果你確定自己的邏輯需要立即返回,可以在self.finish()後立刻return。Tornado在將這個自由留給了你自己。

另外一個理由是,在call stack里讓頂端的函數去彈出一個非頂端的函數,這個邏輯有點奇怪。唯一能夠提供退出的機制就是異常了。但是在正常邏輯裡面使用異常去實現一個功能,也是很怪的邏輯。


沒錯 同理還有self.render/self.write

我們在所有這種response語句前加return 例如 return self.redirect(/)


想要終止函數運行,可以拋出Finish()異常

from tornado.web import Finish
...
...

class IndexHandler(RequestHandler):
def get(self):
self.write("Hello")
raise Finish()
self.write("World")


為什麼finish 後要終止函數運行呢? finnish 以後你可以做任何其他的事情,做self.write 錯誤 是因為和前端的此次http 交互結束了,做其他事情還是可以的。


推薦閱讀:

portal.azure.com這個網站是怎麼做出來的?
flask WEB開發第八章測試登錄的問題,builtins.TypeError,求大神賜教?
記住密碼功能如何設計?
從事網頁前端開發工作的人員英語發音都那麼奇怪嗎?
如何評價beego框架?

TAG:Web開發 | Python | Tornado | Web伺服器軟體 | 計算機網路 | Python框架 |