Tornado asynchttpclient 返回 None
我卡在这个问题上已经好几个小时了。我想用AsyncHTTPClient
来获取一个网站的主页,比如说谷歌。为了实现这个功能,我在同一个类里面定义了一个函数,代码如下:
client = tornado.httpclient.AsyncHTTPClient()
@asynchronous
def getUrlRes(self,url,params,req_type):
req1 = tornado.httpclient.HTTPRequest(url="http://www.google.com", method="GET")
self.client.fetch(req1,self.urlCallBack)
self.finish()
def urlCallBack(self, response):
print response
我哪里做错了呢?
还有一种替代的方法,我试过了,但对我没用,不过对其他人有效:
@asynchronous
@gen.engine
def getUrlRes(self,url,params,req_type):
req1 = tornado.httpclient.HTTPRequest(url="http://www.google.com", method="GET")
response = yield gen.Task(self.client.fetch,req1)
self.finish()
2 个回答
2
如果你想调用一个 gen.engine
函数并从中获取返回值,有几个规则需要遵循:
调用者和被调用者都必须使用
gen.engine
装饰器。需要注意的是,getUrlRes
不需要使用asynchronous
装饰器,只有get
或post
方法需要这个装饰器。被调用的函数需要接受一个
callback
参数。实际的调用是通过
yield gen.Task
来完成的。被调用的函数通过将值传递给回调函数来返回一个值。
把这些规则结合起来,这里有一个请求处理器,它会获取 google.com 的内容并显示出来:
class Main(tornado.web.RequestHandler):
client = tornado.httpclient.AsyncHTTPClient()
@tornado.web.asynchronous
@gen.engine
def get(self):
response = yield gen.Task(self.getUrlRes,
"http://www.google.com", [], "GET")
print 'got response of length', len(response.body)
self.finish(response.body)
@gen.engine
def getUrlRes(self, url, params, req_type, callback):
req1 = tornado.httpclient.HTTPRequest(url, method=req_type)
response = yield gen.Task(self.client.fetch, req1)
callback(response)
你可以在我的文章中了解更多关于 gen.engine
和子程序的内容,文章链接是 使用 gen.engine 重构 Tornado 代码。
顺便提一下,Tornado 3 让这一切变得更简单了,新增了 gen.coroutine
装饰器:
class Main(tornado.web.RequestHandler):
client = tornado.httpclient.AsyncHTTPClient()
@gen.coroutine
def get(self):
response = yield self.getUrlRes("http://www.google.com", [], "GET")
print 'got response of length', len(response.body)
self.finish(response.body)
@gen.coroutine
def getUrlRes(self, url, params, req_type):
req1 = tornado.httpclient.HTTPRequest(url, method=req_type)
response = yield self.client.fetch(req1)
raise gen.Return(response)
@asynchronous
、gen.Task
和显式的回调都不再需要了。函数调用看起来几乎是正常的。协程和普通函数之间主要的区别是 yield
语句,以及使用 raise gen.Return
从子程序返回值。
1
我会使用类似这样的代码
import urllib2
@tornado.web.asynchronous
def getUrlRes(self, url, params, req_type):
def urlCallBack(response):
print "Got response {}".format(response)
self.finish()
self.client.fetch("http://www.google.com?" + urllib2.urlencode(params),
urlCallBack, method=req_type)
这里的关键是,你需要在回调函数里面调用 self.finish
。如果你太早调用 finish
,请求就没有时间完成。
如果你想让调用 getUrlRes
的地方能够获取到完成后的 response
,你可以传递另一个回调函数,然后在请求完成后调用它:
def caller(self):
def _callback(response):
print "Doing something cool"
getUrlRes("google.com", params, "GET", callback=_callback)
@tornado.web.asynchronous
def getUrlRes(self, url, params, req_type, callback=None):
def urlCallBack(response):
print "Got response {}".format(response)
if callback:
_callback(response) # call the passed callback here
self.finish()
self.client.fetch("{}?{}".format(url, urllib2.urlencode(params)),
urlCallBack, method=req_type)