首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >aiohttp:当请求状态代码不是2XX时获得服务器响应

aiohttp:当请求状态代码不是2XX时获得服务器响应
EN

Stack Overflow用户
提问于 2022-01-24 14:28:18
回答 2查看 1.5K关注 0票数 2

我正在使用aiohttp来处理异步http请求,当请求返回4XX错误时,我不知道如何从服务器获得响应。

代码语言:javascript
运行
复制
    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获得响应?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-24 17:31:08

这个问题出现的原因是由于response.ok的副作用。在较早版本的aiohttp (3.7及更低版本)中,response.ok称为response.raise_for_status(),它关闭了TCP会话,导致无法再读取服务器的响应。

要解决这个问题,只需将response = await resp.json()移动到response.ok行的上方,这样就可以预先保存响应。例如:

代码语言:javascript
运行
复制
    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

票数 2
EN

Stack Overflow用户

发布于 2022-08-15 11:55:06

不要在任何地方使用raise_for_status=True作为关键字参数。而是在检索响应、状态代码、消息等之后手动调用response.raise_for_status()

代码语言:javascript
运行
复制
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触发异常。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70835431

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档