跳到主要内容

websocket

WebSocket

lihil 支持 websocket 的使用,你可以使用 WebSocketRoute.ws_handler 来注册一个处理 websocket 的函数。

from lihil import WebSocketRoute, WebSocket, Ignore, use

ws_route = WebSocketRoute("web_socket/{session_id}")

async def ws_factory(ws: Ignore[WebSocket]) -> Ignore[AsyncResource[WebSocket]]:
await ws.accept()
yield ws
await ws.close()

@ws_route.ws_handler
async def ws_handler(
ws: Annotated[WebSocket, use(ws_factory, reuse=False)],
session_id: str,
max_users: int,
):
assert session_id == "session123" and max_users == 5
await ws.send_text("Hello, world!")

lhl = Lihil()
lhl.include_routes(ws_route)

测试

from lihil.vendors import TestClient # 需要安装 httpx

client = TestClient(lhl)
with client:
with client.websocket_connect(
"/web_socket/session123?max_users=5"
) as websocket:
data = websocket.receive_text()
assert data == "Hello, world!"

websocket vs http

  • WebSocket 处理器必须是异步的——由于通信是双向和事件驱动的,处理器必须使用 async def 来支持非阻塞交互。

  • WebSocket 连接不像 HTTP 那样支持请求体——在握手期间没有 Body 参数。所有数据都在连接建立后交换,通常通过通过 WebSocket 协议发送的消息。

  • WebSocket 是有状态的——与无状态的 HTTP 不同,WebSocket 连接持续存在,允许客户端和服务器之间的持续通信。这使得能够维护每个连接的状态(例如用户会话、内存数据)。

  • WebSocket 使用不同的生命周期——它们以 HTTP 握手(通常是 GET 请求)开始,然后升级协议。之后,通信通过 WebSocket 协议完成,而不是 HTTP。

  • 标准的请求/响应模式不适用——WebSocket 是基于消息的,支持实时交互,所以传统的概念(如状态码、每个消息的头部或请求体解析)在初始握手后不直接适用。