From 346eddda067ffe9e5ee7e04086af8b1a3c470679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=B5=E5=91=B5=E3=81=A7=E3=81=99?= <51957264+shoucandanghehe@users.noreply.github.com> Date: Sat, 14 Feb 2026 19:29:11 +0800 Subject: [PATCH] =?UTF-8?q?:bug:=20Fix:=20aiohttp=20=E9=A9=B1=E5=8A=A8?= =?UTF-8?q?=E6=9C=AA=E5=A4=84=E7=90=86=20WSMsgType.CLOSED=20=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=20(#3862)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/drivers/aiohttp.py | 6 +++++- tests/test_driver.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/nonebot/drivers/aiohttp.py b/nonebot/drivers/aiohttp.py index b77e374e..d386f572 100644 --- a/nonebot/drivers/aiohttp.py +++ b/nonebot/drivers/aiohttp.py @@ -323,7 +323,11 @@ class WebSocket(BaseWebSocket): async def _receive(self) -> aiohttp.WSMessage: msg = await self.websocket.receive() - if msg.type in (aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSING): + if msg.type in ( + aiohttp.WSMsgType.CLOSE, + aiohttp.WSMsgType.CLOSING, + aiohttp.WSMsgType.CLOSED, + ): raise WebSocketClosed(self.websocket.close_code or 1006) return msg diff --git a/tests/test_driver.py b/tests/test_driver.py index cf364daa..48f78690 100644 --- a/tests/test_driver.py +++ b/tests/test_driver.py @@ -2,6 +2,7 @@ from http.cookies import SimpleCookie import json from typing import Any, Optional +from aiohttp import ClientSession, ClientWebSocketResponse, WSMessage, WSMsgType import anyio from nonebug import App import pytest @@ -21,6 +22,7 @@ from nonebot.drivers import ( WebSocketClientMixin, WebSocketServerSetup, ) +from nonebot.drivers.aiohttp import WebSocket as AiohttpWebSocket from nonebot.exception import WebSocketClosed from nonebot.params import Depends from utils import FakeAdapter @@ -627,6 +629,42 @@ async def test_websocket_client(driver: Driver, server_url: URL): await anyio.sleep(1) +@pytest.mark.anyio +@pytest.mark.parametrize( + ("msg_type"), + [ + pytest.param("CLOSE", id="aiohttp-close"), + pytest.param("CLOSING", id="aiohttp-closing"), + pytest.param("CLOSED", id="aiohttp-closed"), + ], +) +async def test_aiohttp_websocket_close_frame(msg_type: str) -> None: + class DummyWS(ClientWebSocketResponse): + def __init__(self) -> None: + pass + + @property + def close_code(self) -> None: + return None + + @property + def closed(self) -> bool: + return True + + async def receive(self, timeout: Optional[float] = None) -> WSMessage: # noqa: ASYNC109 + return WSMessage(type=WSMsgType[msg_type], data=None, extra=None) + + async with ClientSession() as session: + ws = AiohttpWebSocket( + request=Request("GET", "ws://example.com"), + session=session, + websocket=DummyWS(), + ) + + with pytest.raises(WebSocketClosed, match=r"code=1006"): + await ws.receive() + + @pytest.mark.parametrize( ("driver", "driver_type"), [