Can not finish a RequestHandler in Tornado with self.finish()

This is my code for Facebook Messenger Platform using Tornado.

class IndexHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
def get(self):
    try:
        mode = self.get_argument("hub.mode")
        token = self.get_argument("hub.verify_token")
        challenge = self.get_argument("hub.challenge")
    except tornado.web.MissingArgumentError:
        self.set_status(400)
        self.write("Bad request")
        self.finish()

    if mode == "subscribe" and token == "secretgarden":
        self.set_status(200)
        self.write(challenge)
        self.finish()
    else:
        self.set_status(403)
        self.write("GTFO")
        self.finish()

The problem is when I run it (lack of hub.mode arg), it will catch MissingArgumentError and throw out:

File "index.py", line 20, in get
if mode == "subscribe" and token == "secretgarden":
UnboundLocalError: local variable 'mode' referenced before assignment

I expect when it catch my MissingArgumentError exception, it will return 400 and end my request. But it still running next code. Did I do anything wrong?

Ps: I have tried add return after self.finish() , it worked, but I have not seen anyone do it. And the docs said:

RequestHandler.finish(chunk=None) Finishes this response, ending the HTTP request.

And I also read this question: Tornado: Can I run code after calling self.finish() in an asynchronous RequestHandler?

Something wrong with my code.


Calling finish does not return from your method. You have to add a return statement, otherwise the next statement in your method is executed.

Actually, you don't need to call finish at all: Tornado request handlers automatically call finish once a coroutine like get completes.

So, to fix your problem, replace your self.finish() calls with return statements.

This answer is related.


Returning at the end of endpoint methods is a good solution, however it won't work if you need to finish (eg by redirecting) from other methods like prepare , initialize and get_current_user , as they are not necessarily last in the call stack. The "official" method is to raise the tornado.web.Finish exception, which will bubble up and break execution from anywhere in the code. I've been using things like this extensively:

class SomeHandler(SomeMoreGenericHandler):

    def prepare(self):
        super().prepare()
        if not self.current_user:
            self.redirect('/login')
            raise tornado.web.Finish
链接地址: http://www.djcxy.com/p/27856.html

上一篇: 如何做单元测试龙卷风+异步def?

下一篇: 无法使用self.finish()完成Tornado中的RequestHandler