Search code examples
tornado

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?

P.s: 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.


Solution

  • 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.