diff --git a/backend/app/api/ws.py b/backend/app/api/ws.py index 9dc1e78..e00dc41 100644 --- a/backend/app/api/ws.py +++ b/backend/app/api/ws.py @@ -132,8 +132,8 @@ async def websocket_endpoint( # 认证通过,建立连接 # ====================================================================== - # 注册连接(内部会调用 websocket.accept()) - await ws_manager.connect(agent_id, websocket) + # 注册连接(内部会调用 websocket.accept(),并回显协商的 subprotocol) + await ws_manager.connect(agent_id, websocket, subprotocol=subprotocol) logger.info(f"坐席 WebSocket 连接已认证: agent_id={agent_id}") try: @@ -289,8 +289,8 @@ async def h5_websocket_endpoint( # 认证通过,建立连接 # ====================================================================== - # 注册员工连接(内部会调用 websocket.accept()) - await ws_manager.connect_employee(employee_id, websocket) + # 注册员工连接(内部会调用 websocket.accept(),并回显协商的 subprotocol) + await ws_manager.connect_employee(employee_id, websocket, subprotocol=subprotocol) logger.info(f"H5员工 WebSocket 连接已认证: employee_id={employee_id}") try: diff --git a/backend/app/services/ws_manager.py b/backend/app/services/ws_manager.py index acc3f1b..9d1a2bd 100644 --- a/backend/app/services/ws_manager.py +++ b/backend/app/services/ws_manager.py @@ -56,7 +56,7 @@ class ConnectionManager: # 坐席连接管理 # ========================================================================== - async def connect(self, agent_id: str, websocket: WebSocket) -> None: + async def connect(self, agent_id: str, websocket: WebSocket, subprotocol: str = "") -> None: """接受坐席 WebSocket 握手并注册连接。 做什么:完成 WebSocket 握手(accept),然后将连接存入映射表 @@ -70,7 +70,10 @@ class ConnectionManager: websocket: FastAPI WebSocket 对象 """ # 完成 WebSocket 握手(必须先 accept 才能收发消息) - await websocket.accept() + # 回显客户端协商的 subprotocol(如 bearer.{token});浏览器在客户端主动 + # 发送了 Sec-WebSocket-Protocol 时,要求服务端也必须回显,否则会以 + # "Sent non-empty 'Sec-WebSocket-Protocol' header but no response" 拒绝握手 + await websocket.accept(subprotocol=subprotocol if subprotocol else None) # 如果该坐席已有连接,先关闭旧连接 # 场景:坐席刷新页面或重新登录,会产生新连接 @@ -163,7 +166,7 @@ class ConnectionManager: # H5员工连接管理 # ========================================================================== - async def connect_employee(self, employee_id: str, websocket: WebSocket) -> None: + async def connect_employee(self, employee_id: str, websocket: WebSocket, subprotocol: str = "") -> None: """接受H5员工 WebSocket 握手并注册连接。 做什么:完成 WebSocket 握手(accept),然后将连接存入员工映射表 @@ -176,7 +179,10 @@ class ConnectionManager: websocket: FastAPI WebSocket 对象 """ # 完成 WebSocket 握手 - await websocket.accept() + # 回显客户端协商的 subprotocol(如 bearer.{token});浏览器在客户端主动 + # 发送了 Sec-WebSocket-Protocol 时,要求服务端也必须回显,否则会以 + # "Sent non-empty 'Sec-WebSocket-Protocol' header but no response" 拒绝握手 + await websocket.accept(subprotocol=subprotocol if subprotocol else None) # 如果该员工已有连接,先关闭旧连接 if employee_id in self.employee_connections: