-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot access an error message when receive 400 #4600
Comments
Hi. You can use a simple solution here. import asyncio
from pprint import pprint
from attr import dataclass
from aiohttp import ClientSession, ClientResponseError, ClientResponse
@dataclass
class ClientResponseMessage:
reason: str
body: str
async def raise_for_status(self: ClientResponse) -> None:
if 400 <= self.status:
# reason should always be not None for a started response
assert self.reason is not None
message = ClientResponseMessage(reason=self.reason, body=await self.text())
self.release()
raise ClientResponseError(
self.request_info,
self.history,
status=self.status,
message=message,
headers=self.headers)
async def main():
try:
async with ClientSession(raise_for_status=raise_for_status) as session:
async with session.get("http://www.mocky.io/v2/5e5e682d310000cef62c254b") as response:
pprint(await response.text())
except ClientResponseError as ex:
pprint(ex.__dict__)
"""
{'headers': <CIMultiDictProxy(...)>,
'history': (),
'message': ClientResponseMessage(reason='Bad Request', body='Some interesting text. You are welcome!'),
'request_info': RequestInfo(...),
'status': 400}
"""
asyncio.run(main()) |
Nope, I don't think this solution is correct.
My version is Related: #3365 (comment) UPD: Lines 550 to 559 in 63a0d10
In the latest code, it does |
Fixed by #3892 |
I just checked I think it will be part of |
Not sure what was wrong, but CI was getting 422s from GitHub. Using a `raise_for_status=True` ClientSession circumvented gidgethubs native error handling logic smothering the HTTP response body where github places critical debugging information. Aiohttp is aware that `raise_for_status` provides no access to the response body. They addressed this in https://github.com/aio-libs/aiohttp/pulls/3892, but that has not been released because 4.0.0 has not yet been released. Another relevant issue: aio-libs/aiohttp#4600.
…ates (#8480) * [ci] better errors on bad github response Not sure what was wrong, but CI was getting 422s from GitHub. Using a `raise_for_status=True` ClientSession circumvented gidgethubs native error handling logic smothering the HTTP response body where github places critical debugging information. Aiohttp is aware that `raise_for_status` provides no access to the response body. They addressed this in https://github.com/aio-libs/aiohttp/pulls/3892, but that has not been released because 4.0.0 has not yet been released. Another relevant issue: aio-libs/aiohttp#4600. * wabhjkladhjksfkdsa * fdsiahfds * wip
This also broke # Will crash while server response 4xx or 5xx
async with aiohttp.request(method=method, url=url, data=data, headers=headers) as resp:
is_ok, resp_data = resp.ok, await resp.json()
# Have to fix in this way
async with aiohttp.request(method=method, url=url, data=data, headers=headers) as resp:
resp_data = await resp.json() # access body before invoke resp.ok
is_ok = resp.ok Hope fixes will release soon. |
FYI @yeralin and everyone, I've implemented the following workaround for this while we are waiting on v4: class MessagePreservingClientResponse(aiohttp.ClientResponse):
async def start(self, connection: aiohttp.connector.Connection) -> aiohttp.ClientResponse:
result = await super().start(connection)
if self.status >= 400:
await self.read() # Avoid a ClientConnectionError later
return result
def raise_for_status(self) -> None:
try:
super().raise_for_status()
except aiohttp.ClientResponseError as err:
try:
coro = self.text()
try:
coro.send(None)
except StopIteration as text:
if text.value:
err.message = text.value
finally:
coro.close()
finally:
raise err
def make_session() -> aiohttp.ClientSession:
# Workaround for https://github.com/aio-libs/aiohttp/issues/4600
return aiohttp.ClientSession(raise_for_status=True, response_class=MessagePreservingClientResponse) Usage: async with make_session() as session:
do your normal stuff... Magic! |
🐞 Describe the bug
While using
aiohttp.client.ClientSession
to send requests and receive responses, I found out that I cannot access a bad response's error message while catchingClientResponseError
becauseaiohttp
simply does not propagate the response content when raisingClientResponseError
here:aiohttp/aiohttp/client_reqrep.py
Lines 879 to 889 in 63a0d10
It only passes
self.status == 400
andself.reason == "BAD REQUEST"
.💡 To Reproduce
💡 Expected behavior
Received
ClientResponseError
should contain a response message received along with 400 response.📋 Logs/tracebacks
📋 Your version of the Python
📋 Your version of the aiohttp/yarl/multidict distributions
📋 Additional context
On the server side, when I change the response from 400 to any non-bad response say 200, I can access passed error message.
Current workaround would be to have
session = ClientSession(raise_for_status=False)
, and handle bad responses manually.🔷 Possible solution
Modify
ClientResponseError
exception to include an error message, convertraise_for_status
method to be async to be able to read the response message, and raiseClientResponseError
with the read message.The text was updated successfully, but these errors were encountered: