【Tornado】HTTP客户端接口-- IOStream 连接在实战项目中的实践
Tornado
Tornado与大多数python web框架不同。它不基于WSGI,通常每个进程只运行一个线程。有关Tornado异步编程方法的更多信息,请参阅用户指南。
虽然在龙卷风中,wsgi模块不是开发的重点。大多数应用程序应该直接使用Tornado自己的界面(如Tornado.web),而不是使用wsgi。
通常,Tornado代码不是线程安全的。Tornado中唯一可以从其他线程安全调用的方法是IOLoop add_ Callback。也可以使用IOLoop run_in_执行器在另一个线程上异步运行阻塞函数,但请注意,它被传递给run_in_。执行器应该避免引用任何Tornado对象。run_inExecutor是与阻塞代码交互的推荐方法。
HTTP客户端接口
提供此接口是为了更容易在同步和异步应用程序之间共享代码。正在运行的应用程序IOLoop必须改用AsyncHTTPClient
http_client = httpclient.HTTPClient()
try:
response = http_client.fetch("http://www.google.com/")
print(response.body)
except httpclient.HTTPError as e:
print("Error: " + str(e))
except Exception as e:
print("Error: " + str(e))
http_client.close()
执行请求并返回HTTPResponse
请求可以是字符串URL或HTTPRequest对象。如果它是一个字符串,我们将构造一个HTTPRequest以使用任何其他禁运:HTTPRequest(request,**kwargs)
如果在提取过程中发生错误,我们将抛出HTTPError,除非raise_theerror关键字参数设置为false。
AsyncHTTPClient.configure(
None, defaults=dict(user_agent="MyUserAgent"))
# or with force_instance:
client = AsyncHTTPClient(force_instance=True,
defaults=dict(user_agent="MyUserAgent"))
这个类的构造函数在几个方面都很神奇:它实际上创建了一个特定于实现的子类的实例,并且该实例被重用为伪单例(每个IOLoop)关键字参数force_instance=True可以用来抑制这种单例行为。除非force_Instance=True,否则不应向AsyncHTTPClient构造函数传递任何参数。实现子类及其构造函数的参数可以使用静态方法configure()设置
所有AsyncHTTPClient实现都支持defaults关键字参数,该参数可用于设置HTTPRequest属性。
import tornado.ioloop
import tornado.iostream
import socket
async def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
stream = tornado.iostream.IOStream(s)
await stream.connect(("friendfeed.com", 80))
await stream.write(b"GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n")
header_data = await stream.read_until(b"\r\n\r\n")
headers = {}
for line in header_data.split(b"\r\n"):
parts = line.split(b":")
if len(parts) == 2:
headers[parts[0].strip()] = parts[1].strip()
body_data = await stream.read_bytes(int(headers[b"Content-Length"]))
print(body_data)
stream.close()
if __name__ == '__main__':
tornado.ioloop.IOLoop.current().run_sync(main)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
stream = tornado.iostream.IOStream(s)
stream.connect(("friendfeed.com", 80), send_request)
tornado.ioloop.IOLoop.current().start()
执行请求并异步返回HTTPResponse
请求可以是字符串URL或HTTPRequest对象。如果它是一个字符串,我们将构造一个HTTPRequest以使用任何其他禁运:HTTPRequest(request,**kwargs)
此方法返回Future,结果是HTTPResponse。默认情况下,Future将改进HTTPError。如果请求返回非200响应代码(如果无法联系服务器,也可能导致其他错误)。相反,如果raise_ErrorIf设置为false,则无论响应代码如何,都将始终返回响应。
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
如果给定回调,将使用HTTPResponse。在回调接口中,HTTPError不会自动升级。相反,必须检查响应错误属性或调用其rethrow方法。
此回调参数已被删除。改用返回的Future。
此raise_Theerror=False参数仅在HTTPError使用非200响应代码而不是禁用所有错误时才会影响。
Classmethodconfigure(impl:Union[None,str,Type[tornado.util.Configuratible]],**kwargs:Any)→ 无[源代码
配置AsyncHTTPClient要使用的子类。
h.add("Set-Cookie", "A=B")
h.add("Set-Cookie", "C=D")
h["set-cookie"]
'A=B,C=D'
h.get_list("set-cookie")
['A=B', 'C=D']
AsyncHTTPClient()实际上创建了子类的一个实例。可以使用类对象或该类的完全限定名称(或None使用默认值SimpleAsyncHTTPClient)
如果提供了其他关键字参数,它们将传递给每个创建的子类实例的构造函数。关键字参数max_Clients确定每个操作IOLoop可以并行执行的fetch()操作的最大同时数。根据使用的实现类,可能支持其他参数。
h = HTTPHeaders.parse("Content-Type: text/html\r\nContent-Length: 42\r\n")
sorted(h.items())
[('Content-Length', '42'), ('Content-Type', 'text/html')]
async def main():
# do stuff...
if __name__ == '__main__':
IOLoop.current().run_sync(main)
仅当传递给构造函数的套接字以前未连接时调用。地址参数的格式与传递给iostream构造函数的套接字类型的for socket Connect的格式相同,例如(ip,port)元组。此处接受主机名,但IOLoop将被同步解析并阻止。如果您有主机名而不是IP地址,TCPClient建议使用类而不是直接调用此方法。TCPClient将执行异步DNS解析并处理IPv4和IPv6。
如果未指定回调,则在连接完成时将不带参数地调用回调;如果未指定,此方法将返回Future(成功连接的结果将是流本身)。
{
# Hostname to host or ip
"example.com": "127.0.1.1",
# Host+port to host+port
("login.example.com", 443): ("localhost", 1443),
# Host+port+address family to host+port
("login.example.com", 443, socket.AF_INET6): ("::1", 1443),
}
在SSL模式下,server_主机名参数将用于证书验证(SSL_options中除外)和sni。
请注意,调用是安全的IOStream Write当连接挂起时,在这种情况下,数据将在连接就绪后立即写入。在连接到套接字之前,调用IOStream读取方法可以在某些平台上工作,但它不可移植。
from tornado.tcpserver import TCPServer
from tornado.iostream import StreamClosedError
from tornado import gen
class EchoServer(TCPServer):
async def handle_stream(self, stream, address):
while True:
try:
data = await stream.read_until(b"\n")
await stream.write(data)
except StreamClosedError:
break
- 点赞
- 收藏
- 关注作者
评论(0)