如何让aiohttp.ClientSession忽略或接受含空格的响应头?
解决aiohttp因响应头含空格抛出的Invalid header token错误
针对API返回含空格的响应头(如Status Code: 200)导致aiohttp解析失败的问题,提供两种可行的临时解决方案:
方案一:全局修改头部解析规则,允许空格
通过monkey patch修改aiohttp内部的头部字符校验逻辑,让它接受空格作为头部名称的一部分:
import aiohttp from aiohttp.http_parser import _is_token # 保存原始校验函数 original_is_token = _is_token # 重写校验逻辑,允许空格字符 def patched_is_token(c: int) -> bool: if c == ord(' '): return True return original_is_token(c) # 替换原函数 aiohttp.http_parser._is_token = patched_is_token # 正常发起请求 async def fetch_data(): async with aiohttp.ClientSession() as session: async with session.get("https://目标API地址") as resp: print(f"状态码: {resp.status}") print("响应头:", dict(resp.headers))
优缺点:实现简单,所有含空格的头部都会被正常解析,但违反HTTP规范,可能带来潜在的兼容性风险。
方案二:自定义解析器,跳过解析失败的头部
创建自定义的响应解析器,捕获头部解析错误并跳过有问题的条目,不影响其他正常头部:
import aiohttp from aiohttp.http_parser import HttpResponseParser class TolerantHttpResponseParser(HttpResponseParser): def _parse_header(self, line: bytes) -> tuple[bytes, bytes] | None: try: # 尝试用原始逻辑解析头部 return super()._parse_header(line) except ValueError: # 解析失败时跳过该头部 return None # 使用自定义解析器创建连接器 connector = aiohttp.TCPConnector(response_parser=TolerantHttpResponseParser) # 发起请求 async def fetch_data(): async with aiohttp.ClientSession(connector=connector) as session: async with session.get("https://目标API地址") as resp: print(f"状态码: {resp.status}") print("响应头:", dict(resp.headers))
优缺点:仅跳过解析失败的头部,不会全局修改HTTP规范的校验逻辑,安全性更高,但需要自定义解析器类。
注意事项
- 以上方案针对aiohttp 3.10.5版本有效,后续版本内部实现若有变更,需对应调整代码。
- 这两种方法均为临时 workaround,核心问题是API违反HTTP规范,建议优先推动API提供方修复响应头格式问题。
内容的提问来源于stack exchange,提问作者Matthew Young
相关产品推荐
相关产品推荐

