如何修复Python中hyper库的FRAME_SIZE_ERROR连接错误
解决HTTP/2请求中的FRAME_SIZE_ERROR问题
问题场景
需要向单元测试REST API服务器发送HTTP/2的GET和POST请求,使用requests库结合hyper的HTTP20Adapter实现,但运行时抛出帧大小错误。
原始代码如下:
import requests from hyper.contrib import HTTP20Adapter s = requests.Session() data={ "param1": 3000, "param2": 10, "param3": 2, "param4": "2200", "param5": "800", "param6": "2200", "param7": "2000", "param8": "1700", "param9": "1200", "param10": 60, "param11": "23:00-22:59", "param12": 3, "param13": True, "param14": 85 } s.verify="/path to ca-cert file" s.mount('https://', HTTP20Adapter()) r = s.post('https://localhost:1000/config', data=data) print(r.status_code) print(r.url)
报错信息
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.9/site-packages/requests/sessions.py", line 635, in post return self.request("POST", url, data=data, json=json, **kwargs) File "/usr/local/lib/python3.9/site-packages/requests/sessions.py", line 587, in request resp = self.send(prep, **send_kwargs) File "/usr/local/lib/python3.9/site-packages/requests/sessions.py", line 701, in send r = adapter.send(request, **kwargs) File "/usr/local/lib/python3.9/site-packages/hyper/contrib.py", line 118, in send resp = conn.get_response() File "/usr/local/lib/python3.9/site-packages/hyper/common/connection.py", line 136, in get_response return self._conn.get_response(*args, **kwargs) File "/usr/local/lib/python3.9/site-packages/hyper/http20/connection.py", line 305, in get_response return HTTP20Response(stream.getheaders(), stream) File "/usr/local/lib/python3.9/site-packages/hyper/http20/stream.py", line 240, in getheaders self._recv_cb(stream_id=self.stream_id) File "/usr/local/lib/python3.9/site-packages/hyper/http20/connection.py", line 787, in _recv_cb self._single_read() File "/usr/local/lib/python3.9/site-packages/hyper/http20/connection.py", line 738, in _single_read raise ConnectionError(error_string) hyper.http20.exceptions.ConnectionError: Encountered error FRAME_SIZE_ERROR 0x6: Frame size incorrect
解决方法
这个错误是因为HTTP/2连接的帧大小不匹配,需要自定义流量控制管理器来适配服务器的帧大小设置。具体步骤如下:
- 导入
BaseFlowControlManager类,自定义流量控制管理器; - 继承
HTTP20Adapter,重写build_connection方法,在创建HTTP20连接时传入自定义的流量控制管理器; - 将自定义的适配器挂载到requests Session上。
修改后的完整代码:
import requests from hyper.contrib import HTTP20Adapter from hyper.http20.window import BaseFlowControlManager # 自定义流量控制管理器 class StupidFlowControlManager(BaseFlowControlManager): def increase_window_size(self, frame_size): return frame_size # 继承HTTP20Adapter,自定义连接创建逻辑 class CustomHTTP20Adapter(HTTP20Adapter): def build_connection(self, host, port, secure): # 创建连接时传入自定义的window_manager conn = super().build_connection(host, port, secure) conn._conn.window_manager = StupidFlowControlManager() return conn s = requests.Session() data={ "param1": 3000, "param2": 10, "param3": 2, "param4": "2200", "param5": "800", "param6": "2200", "param7": "2000", "param8": "1700", "param9": "1200", "param10": 60, "param11": "23:00-22:59", "param12": 3, "param13": True, "param14": 85 } s.verify="/path to ca-cert file" # 挂载自定义的适配器 s.mount('https://', CustomHTTP20Adapter()) # 发送POST请求 r = s.post('https://localhost:1000/config', json=data) # 建议用json参数自动序列化,避免表单编码问题 print(r.status_code) print(r.url)
补充说明
- 代码中把
data=data改为json=data,因为大多数REST API期望接收JSON格式的请求体,而data参数默认会以表单形式编码,可能不符合服务器要求; - 如果自定义的流量控制管理器仍不生效,可以尝试调整帧大小的具体数值,比如返回一个固定的较大值(如
return 65535,HTTP/2最大帧大小)。
内容的提问来源于stack exchange,提问作者user5759780
相关产品推荐
相关产品推荐

