fix(ws): echo WebSocket subprotocol on accept to fix browser handshake
后端 ws_manager.connect/connect_employee 与 ws.py 调用未回显客户端协商的 Sec-WebSocket-Protocol (bearer.{token}),导致浏览器以 'Sent non-empty Sec-WebSocket-Protocol header but no response' 拒绝握手,H5/坐席 WS 实际一直走 3s 轮询兜底而非流式打字机。现回显 subprotocol 修复握手。验证:dev 真实浏览器 E2E 343 帧 typewriter;生产 docker cp 部署后日志显示 H5/坐席 WS 连接 [accepted] 且 连接建立。
This commit is contained in:
@@ -132,8 +132,8 @@ async def websocket_endpoint(
|
|||||||
# 认证通过,建立连接
|
# 认证通过,建立连接
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|
||||||
# 注册连接(内部会调用 websocket.accept())
|
# 注册连接(内部会调用 websocket.accept(),并回显协商的 subprotocol)
|
||||||
await ws_manager.connect(agent_id, websocket)
|
await ws_manager.connect(agent_id, websocket, subprotocol=subprotocol)
|
||||||
logger.info(f"坐席 WebSocket 连接已认证: agent_id={agent_id}")
|
logger.info(f"坐席 WebSocket 连接已认证: agent_id={agent_id}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -289,8 +289,8 @@ async def h5_websocket_endpoint(
|
|||||||
# 认证通过,建立连接
|
# 认证通过,建立连接
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|
||||||
# 注册员工连接(内部会调用 websocket.accept())
|
# 注册员工连接(内部会调用 websocket.accept(),并回显协商的 subprotocol)
|
||||||
await ws_manager.connect_employee(employee_id, websocket)
|
await ws_manager.connect_employee(employee_id, websocket, subprotocol=subprotocol)
|
||||||
logger.info(f"H5员工 WebSocket 连接已认证: employee_id={employee_id}")
|
logger.info(f"H5员工 WebSocket 连接已认证: employee_id={employee_id}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -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 握手并注册连接。
|
||||||
|
|
||||||
做什么:完成 WebSocket 握手(accept),然后将连接存入映射表
|
做什么:完成 WebSocket 握手(accept),然后将连接存入映射表
|
||||||
@@ -70,7 +70,10 @@ class ConnectionManager:
|
|||||||
websocket: FastAPI WebSocket 对象
|
websocket: FastAPI WebSocket 对象
|
||||||
"""
|
"""
|
||||||
# 完成 WebSocket 握手(必须先 accept 才能收发消息)
|
# 完成 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员工连接管理
|
# 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 握手并注册连接。
|
"""接受H5员工 WebSocket 握手并注册连接。
|
||||||
|
|
||||||
做什么:完成 WebSocket 握手(accept),然后将连接存入员工映射表
|
做什么:完成 WebSocket 握手(accept),然后将连接存入员工映射表
|
||||||
@@ -176,7 +179,10 @@ class ConnectionManager:
|
|||||||
websocket: FastAPI WebSocket 对象
|
websocket: FastAPI WebSocket 对象
|
||||||
"""
|
"""
|
||||||
# 完成 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:
|
if employee_id in self.employee_connections:
|
||||||
|
|||||||
Reference in New Issue
Block a user