我正在使用aiohttp来处理异步http请求,当请求返回4XX错误时,我不知道如何从服务器获得响应。
async def login(self, username: str, password: str) -> None:
...
async with aiohttp.ClientSession(headers=self._headers) as session:
async with session.post(route, data=data, headers=self._headers) as resp:
if resp.ok:
response = await resp.json()
self._headers['Authorization'] = 'Bearer ' + response['access_token']
else:
response = await resp.json()
raise InvalidGrant(response)
如果响应返回一个2XX代码,那么使用resp.json()
可以正常工作,但是当它返回一个4XX错误(在本例中是400
)时,它会引发一个aiohttp.client_exceptions.ClientConnectionError
,并且不会让我得到服务器发送的响应(这是我需要的,因为服务器返回某种比Bad Request
更具描述性的错误消息)。如果请求不成功,是否无法通过aiohttp获得响应?
发布于 2022-01-24 17:31:08
这个问题出现的原因是由于response.ok
的副作用。在较早版本的aiohttp (3.7及更低版本)中,response.ok
称为response.raise_for_status()
,它关闭了TCP会话,导致无法再读取服务器的响应。
要解决这个问题,只需将response = await resp.json()
移动到response.ok
行的上方,这样就可以预先保存响应。例如:
async def login(self, username: str, password: str) -> None:
...
async with aiohttp.ClientSession(headers=self._headers) as session:
async with session.post(route, data=data, headers=self._headers) as resp:
response = await resp.json()
if resp.ok:
self._headers['Authorization'] = 'Bearer ' + response['access_token']
else:
raise InvalidGrant(response)
这一问题已在aioHTTP3.8中得到修正:https://github.com/aio-libs/aiohttp/pull/5404
发布于 2022-08-15 11:55:06
不要在任何地方使用raise_for_status=True作为关键字参数。而是在检索响应、状态代码、消息等之后手动调用response.raise_for_status()
async def fetch_feed_items(
feed: Feed, request_headers: CIMultiDict, session: aiohttp.ClientSession
) -> Tuple[Feed, CIMultiDictProxy, int, str]:
"""Load data from url.
Args:
feed (Feed): object which contains url, etag, last_modified and feed_id
request_headers (CIMultiDict): headers sent with the request
session (aiohttp.ClientSession): an aiohttp.ClientSession instance
Returns:
Tuple[Feed, CIMultiDictProxy, int, str]: Returns information about the source
"""
response_headers = {}
text = ""
status = None
try:
async with session.get(feed.url, headers=request_headers, ssl=False) as response:
text = await response.text()
response_headers = response.headers
status = response.status
message = response.reason
# Dont use raise_for_status=True option as it doesn't capture the status code and message
response.raise_for_status()
except aiohttp.ClientError as e:
print(feed.url, "aiohttp client error", e)
except aiohttp.http.HttpProcessingError as e:
print(feed.url, "aiohttp processing error", e)
except asyncio.TimeoutError as e:
print(feed.url, "asyncio timeout error", e)
except Exception as e:
print(feed.url, "generic error", e)
finally:
return feed, response_headers, status, message, text
在上面的片段中,当出现4xx或5xx错误时,响应头、状态、消息值首先存储在变量中,然后response.raise_for_status触发异常。
https://stackoverflow.com/questions/70835431
复制相似问题