【Tornado】HTTP客户端接口-- IOStream 连接在实战项目中的实践

举报
黎燃 发表于 2024/08/14 22:02:10 2024/08/14
【摘要】 TornadoTornado与大多数python web框架不同。它不基于WSGI,通常每个进程只运行一个线程。有关Tornado异步编程方法的更多信息,请参阅用户指南。虽然在龙卷风中,wsgi模块不是开发的重点。大多数应用程序应该直接使用Tornado自己的界面(如Tornado.web),而不是使用wsgi。通常,Tornado代码不是线程安全的。Tornado中唯一可以从其他线程安全...

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
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。