python 使用 httpx 发送http2.0 请求
待续
python 使用 httpx 发送http2.0 请求
摘要
python
中最早支持HTTP/2
的是hyper,但这个库近几年都不更新了。最近这批开发人员又出了一个新库,用来支持HTTP/2
,hyper-h2,这个库看提交时间是最近才开始开发的,不过目前看来还没有支持异步的计划。
这里,我要介绍的是另一个HTTP/2
的库httpx
,也是新开发的,准确的来说还是beta
版本。同时支持HTTP/1.1
和HTTP/2
。而且还支持发送异步请求。就笔者写这篇文章的时候,这个项目的star
已经有5.3k
了。httpx
官方文档地址,如果觉得笔者啰嗦,可以直接阅读官方文档,下面文章只是一篇简单的教程。
安装
# 只支持 python3.6 以上版本
pip install httpx
http/2 支持
客户端请求
更有效地利用网络资源
当您使用《快速入门》指南中记录的顶级API进行请求时,HTTPX必须为每个单个请求建立一个新的连接(连接不会被重用)。随着对主机的请求数量增加,这很快变得效率低下。
另一方面,Client实例使用HTTP连接池。这意味着当您向同一主机发出多个请求时,它们Client将重用基础的TCP连接,而不是为每个单个请求重新创建一个。
与使用顶级API相比,这可以带来显着的性能改进,包括:
- 减少了请求之间的延迟(无握手)。
- 减少CPU使用率和往返次数。
- 减少网络拥塞。
额外功能
Client 实例还支持顶级API所不具备的功能,例如:
- Cookie跨请求的持久性。
- 在所有传出请求中应用配置。
- 通过HTTP代理发送请求。
- 使用HTTP / 2。
一般建议:建议使用a Client作为上下文管理器。这将确保离开with模块时正确清理连接:
同步
>>> headers = {'X-Auth': 'from-client'}
>>> params = {'client_id': 'client1'}
>>> with httpx.Client(headers=headers, params=params, http2=True) as client:
# with 内部请求共用一个client,参数也共用
# 替换client的参数
... headers = {'X-Custom': 'from-request'}
... params = {'request_id': 'request1'}
... r = client.get('https://example.com', headers=headers, params=params)
异步
async with httpx.AsyncClient(http2=True) as client:
...
复杂示例,APNS异步推送到多用户
可参考完整实现代码
import httpx
import asyncio
async def http2conn(device_token, client, content):
r = await client.post(f"/3/device/{device_token}", json=content)
logger.info('ios push: ' + device_token)
logger.info(r.status_code)
# 您可以参考apple apns官方文档,重组下面的推送参数
# 此函数可以在协程中直接调用
async def ios_push(title, text, product, product_id, device_tokens='', **kwargs):
"""
kwargs={'product':'', 'product_id': '产品id', 'device_token': 'device_token'}
"""
content = {
"aps": {
"alert": {
"title": title,
"body": text,
},
},
"classify": product,
"carousel_id": product_id,
}
path = 'dev_certificates.pem'
device_tokens = device_tokens.split(',')
number = len(device_tokens) // 1000
async with httpx.AsyncClient(base_url=settings.IOS_URL, cert=path, http2=True) as client:
http2conn_def = partial(http2conn, client=client, content=content)
for i in range(number + 1):
limit = i * 1000
await asyncio.gather(*[http2conn_def(device_token) for device_token in device_tokens[limit:limit + 1000]])
http/1 支持
简单请求
>>> r = httpx.get('https://httpbin.org/get')
>>>> r = httpx.post('https://httpbin.org/post', data={'key': 'value'})
>>> r = httpx.put('https://httpbin.org/put', data={'key': 'value'})
>>> r = httpx.delete('https://httpbin.org/delete')
>>> r = httpx.head('https://httpbin.org/get')
>>> r = httpx.options('https://httpbin.org/get')
携带参数,文件,自定义请求头
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
>>>> headers = {'user-agent': 'my-app/0.0.1'}
>>> cookies = {"peanut": "butter"}
>>> r = httpx.post('https://httpbin.org/post', data={'key': 'value'}, headers=headers, files=files, cookies=cookies)
>>> r.headers
Headers({
'content-encoding': 'gzip',
'transfer-encoding': 'chunked',
'connection': 'close',
'server': 'nginx/1.0.4',
'x-runtime': '148ms',
'etag': '"e1ca502697e5c9317743dc078f67693f"',
'content-type': 'application/json'
})
>>> r.status_code
同步
>>> headers = {'X-Auth': 'from-client'}
>>> params = {'client_id': 'client1'}
>>> proxies = {
... "http": "http://127.0.0.1:3080",
... "https": "http://127.0.0.1:3081"
... }
>>> with httpx.Client(headers=headers, params=params, proxies=proxies) as client:
... headers = {'X-Custom': 'from-request'}
... params = {'request_id': 'request1'}
... r = client.get('https://example.com', headers=headers, params=params)
异步
HTTPX
默认情况下提供标准的同步API,但是如果需要,还可以为您提供异步客户端的选项。
异步是一种并发模型,其效率远远高于多线程,并且可以提供显着的性能优势并支持使用长期存在的网络连接(例如WebSockets
)。
import asyncio
import httpx
async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
asyncio.run(main())
总结
http/1
和 http/2
的API基本一致,可参靠上述实现http/1
,另外http/2
只支持客户端方式请求。
这里只是简单的介绍,如需要复杂的功能(流式传输,代理请求,SSL
证书,.netrc
支持等)还是仔细研读官方文档以及源码。
更多推荐
所有评论(0)