问题描述
我正在尝试将hyper.contrib
HTTP20Adapter
与here所述的requests
模块一起使用,但是即使遵循了以这种方式使用HTTP / 2的示例,它仍然使用HTTP / 1.1。结果为ConnectionResetError
,并且从未尝试使用HTTP / 2。如果我使用hyper HTTPConnection
,它也使用HTTP / 1.1并失败。但是,如果我使用HTTP20Connection
,它将使用HTTP / 2并成功。是否可以通过requests
强制HTTP20Adapter
仅使用HTTP / 2?
使用HTTPConnection
进行首次测试。 Wireshark跟踪确认这导致HTTP / 1.1 GET和连接重置。
>>> from hyper import HTTPConnection
>>> c = HTTPConnection('10.11.22.33:8080')
>>> c.request('GET','/my/path/')
>>> resp = c.get_response()
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/connection.py",line 129,in get_response
return self._conn.get_response(*args,**kwargs)
File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/http11/connection.py",line 203,in get_response
self._sock.fill()
File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/bufsocket.py",line 169,in fill
raise ConnectionResetError()
ConnectionResetError
使用HTTP20Connection
进行第二次测试。这导致HTTP / 2 GET请求和成功的响应。
>>> from hyper import HTTP20Connection
>>> c = HTTP20Connection('10.11.22.33:8080')
>>> c.request('GET','/my/path/')
1
>>> resp = c.get_response()
>>> print(resp.headers)
HTTPHeaderMap([(b'server',b'nginx/1.14.1'),(b'date',b'Wed,12 Aug 2020 13:29:34 GMT'),(b'content-type',b'application/problem+json'),(b'3gpp-sbi-message-priority',b'10'),(b'x-envoy-upstream-service-time',b'109')])
第三次测试,将requests
与适配器一起使用。这也导致了HTTP / 1.1请求和ConnectionResetError
。在网上看不到HTTP / 2。
>>> import requests
>>> from hyper.contrib import HTTP20Adapter
>>>
>>> s = requests.Session()
>>> s.mount('http://10.11.22.33:8080',HTTP20Adapter())
>>> s
<requests.sessions.Session object at 0x7f68f3487f28>
>>>
>>>
>>> r = s.get('http://10.11.22.33:8080/my/path/')
Traceback (most recent call last):
File "<stdin>",in <module>
File "/root/Python/myApp/lib64/python3.6/site-packages/requests/sessions.py",line 543,in get
return self.request('GET',url,**kwargs)
File "/root/Python/myApp/lib64/python3.6/site-packages/requests/sessions.py",line 530,in request
resp = self.send(prep,**send_kwargs)
File "/root/Python/myApp/lib64/python3.6/site-packages/requests/sessions.py",line 643,in send
r = adapter.send(request,**kwargs)
File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/contrib.py",line 80,in send
resp = conn.get_response()
File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/connection.py",in fill
raise ConnectionResetError()
ConnectionResetError
由于框架的其余部分正在使用requests
模块,因此我真的需要进行最后的测试。
解决方法
我建议您在此处使用一个猴子补丁。
编写如下所示的自定义请求,以使用HTTP20Connection代替HTTP11Connection
from hyper.http20.connection import HTTP20Connection
def custom_request(self,method,url,body=None,headers=None):
headers = headers or {}
if self._conn.__class__.__name__ == 'HTTP11Connection':
self._conn = HTTP20Connection(
self._host,self._port,**self._h2_kwargs
)
try:
return self._conn.request(
method=method,url=url,body=body,headers=headers
)
except TLSUpgrade as e:
assert e.negotiated in H2_NPN_PROTOCOLS
self._conn = HTTP20Connection(
self._host,**self._h2_kwargs
)
self._conn._sock = e.sock
self._conn._send_preamble()
return self._conn.request(
method=method,headers=headers
)
此后,您可以按以下步骤进行猴子补丁
from hyper.common.connection import HTTPConnection
HTTPConnection.request = custom_request