How to use POST method in Tornado?

user1363445 picture user1363445 · Apr 29, 2012 · Viewed 41.7k times · Source

I'm trying to use Tornado to start a server and post a string to it. I've found lots of examples of how to write the post method in the handler class, but no examples of how to write the post request. My current code does cause the post method to execute, but get_argument isn't getting the data--it just prints the default "No data received" every time. What am I doing wrong?

My code looks like this:

class MainHandler(tornado.web.RequestHandler):
    def post(self):
        data = self.get_argument('body', 'No data received')
        self.write(data)

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

if __name__ == "__main__":

    def handle_request(response):
        if response.error:
            print "Error:", response.error
        else:
            print response.body
        tornado.ioloop.IOLoop.instance().stop()

    application.listen(8888)    
    test = "test data"
    http_client = tornado.httpclient.AsyncHTTPClient()
    http_client.fetch("http://0.0.0.0:8888", handle_request, method='POST', headers=None, body=test)
    tornado.ioloop.IOLoop.instance().start()

Is putting the string I want to send in the "body" parameter the right thing to do? In some examples I've seen, like here, it seems people create their own parameters, but if I try to add a new parameter to the request, like

http_client.fetch("http://0.0.0.0:8888", handle_request, method='POST', headers=None, data=test)

I just get an error saying "TypeError: init() got an unexpected keyword argument 'data'"

Thanks!

Answer

Theron Luhn picture Theron Luhn · Apr 29, 2012

it seems people create their own parameters

Not quite. From the docs:

fetch(request, **kwargs)

Executes a request, returning an HTTPResponse.

The request may be either a string URL or an HTTPRequest object. If it is a string, we construct an HTTPRequest using any additional kwargs: HTTPRequest(request, **kwargs)

(Link)

So the kwargs are actually from this method.

Anyways, to the real meat of the problem: How do you send POST data? You were on the right track, but you need to url encode your POST data and use that as your body kwarg. Like this:

import urllib
post_data = { 'data': 'test data' } #A dictionary of your post data
body = urllib.urlencode(post_data) #Make it into a post request
http_client.fetch("http://0.0.0.0:8888", handle_request, method='POST', headers=None, body=body) #Send it off!

Then to get the data:

data = self.get_argument('data', 'No data received')