websocket通信

"WebSocket 允许客户端和服务器在连接建立后随时互相发送数据,而无需每次交互都重新建立连接。"我想请问,第一次前端往后端发送数据时,传递的数据应该满足接口的参数内容,在第一次建立连接后之后的数据传递还是要满足接口的参数吗,还是直接利用这个管道随意的传输数据就可以。

一、WebSocket 基础

WebSocket 是一种在客户端(如浏览器)和服务器之间建立持久化的全双工通信通道的协议。与传统的 HTTP 请求-响应模式不同,WebSocket 允许客户端和服务器在连接建立后随时互相发送数据,而无需每次交互都重新建立连接。这使得 WebSocket 特别适合实时应用,如聊天系统、实时通知、在线游戏等。

二、WebSocket 数据传输的基本原则

虽然 WebSocket 提供了高度的灵活性,允许在客户端和服务器之间发送任意类型的数据,但为了确保通信的可靠性和可维护性,遵循一定的数据结构和协议是非常重要的。以下是一些关键点:

  1. 一致的数据格式
    • JSON 格式:通常情况下,WebSocket 通信中使用 JSON 格式的数据,因为它易于解析和处理。
    • 自定义协议:可以根据项目需求定义自定义的数据协议,以确保双方能够正确理解和处理消息。
  2. 消息类型和结构
    • 初始化消息:在连接建立时,前端可能需要发送初始化消息(如认证信息、会话参数等)。
    • 业务消息:连接建立后,前端和服务器之间的消息应遵循预定义的结构,以便双方能够正确解析和处理。
  3. 错误处理
    • 定义明确的错误消息结构,便于前端和后端识别和处理错误情况。
  4. 版本控制
    • 如果项目发展需要,可以在消息中包含版本信息,以支持协议的升级和兼容性。

三、具体到你的项目

结合你提供的 api/v1/chat.pychat/manager.py 代码,我们可以更具体地讨论 WebSocket 数据传输的流程和规范。

1. 初始连接和认证

api/v1/chat.py 中,定义了一个 WebSocket 端点 /chat/{flow_id}。当前端通过这个端点建立连接时,后端会进行认证和流数据验证,然后将连接交给 ChatManager 进行处理。

前端示例代码

javascript 复制代码
const flow_id = "example_flow_id"; // 流程ID
const chat_id = "example_chat_id"; // 聊天ID
const token = "your_jwt_token";    // JWT 认证令牌

// 建立 WebSocket 连接
const socket = new WebSocket(`ws://yourserver.com/api/v1/chat/${flow_id}?chat_id=${chat_id}&t=${token}`);

// 连接成功
socket.onopen = function(event) {
    console.log("WebSocket 连接已建立");
    // 发送初始化消息
    socket.send(JSON.stringify({ "message": "Hello, server!", "flow_id": flow_id, "chat_id": chat_id }));
};

// 接收消息
socket.onmessage = function(event) {
    const message = JSON.parse(event.data);
    console.log("收到消息:", message);
    // 在页面上显示消息
};

// 连接关闭
socket.onclose = function(event) {
    console.log("WebSocket 连接已关闭");
};

// 连接错误
socket.onerror = function(error) {
    console.error("WebSocket 错误:", error);
};

解释

  • 连接 URL :包含 flow_idchat_id 和 JWT 认证令牌 t,用于后端的认证和会话识别。
  • 初始化消息 :在连接建立后,前端发送一条包含 messageflow_idchat_id 的 JSON 消息。
2. 后端处理连接和消息

chat/manager.py 中,ChatManager 类负责管理 WebSocket 连接和消息传递。handle_websocket 函数是核心处理函数,负责接收和处理前端发送的消息,并发送响应。

关键流程

  1. 建立连接
    • 后端通过 await self.connect(flow_id, chat_id, websocket) 接受连接,并将其存储在 active_connections 中。
  2. 接收消息
    • 使用 await websocket.receive_json() 异步接收来自前端的 JSON 消息。
  3. 处理消息
    • 调用 ChatClient.handle_message(payload) 处理接收到的消息。
  4. 发送响应
    • 通过 send_jsonsend_message 方法将处理结果发送回前端。

关键函数示例

python 复制代码
async def handle_websocket(
        self,
        flow_id: str,
        chat_id: str,
        websocket: WebSocket,
        user_id: int,
        gragh_data: dict = None,
):
    await self.connect(flow_id, chat_id, websocket)
    try:
        while True:
            try:
                json_payload_receive = await asyncio.wait_for(websocket.receive_json(), timeout=2.0)
            except asyncio.TimeoutError:
                json_payload_receive = ''
            payload = json.loads(json_payload_receive) if json_payload_receive else {}
            await chat_client.handle_message(payload)
    except WebSocketDisconnect as e:
        logger.info('Client disconnected: {}'.format(e))
    except Exception as e:
        logger.exception(e)
        await self.close_client(client_key, code=status.WS_1011_INTERNAL_ERROR, reason='Internal Error')
    finally:
        await self.close_client(client_key, code=status.WS_1000_NORMAL_CLOSURE, reason='Client disconnected')

解释

  • 消息接收循环:持续接收前端发送的消息,并处理。
  • 异常处理:捕获断开连接和其他异常,确保资源被正确释放。
  • 资源清理 :在 finally 块中,关闭连接并移除相关资源。

四、第一次发送与后续消息的区别

首次发送数据

  • 结构 :通常需要包含认证信息或会话初始化参数,如 flow_idchat_id 和 JWT 认证令牌。
  • 目的:用于建立会话、验证用户身份和初始化聊天上下文。

后续消息传递

  • 结构:应继续遵循预定义的消息结构,以确保前后端能够正确解析和处理数据。
  • 灵活性:虽然 WebSocket 允许发送任意数据,但为了保持通信的一致性和可维护性,建议继续使用一致的数据格式和协议。
  • 示例:
    • 发送消息 :前端发送包含 messageflow_idchat_id 的 JSON 消息。
    • 接收响应 :后端处理消息后,发送结构化的响应,如 ChatMessage 对象的 JSON 表示。

为什么需要一致的数据结构

  1. 可维护性:一致的数据结构使得前后端代码更易理解和维护。
  2. 错误减少:预定义的消息格式可以减少因数据不一致导致的解析错误。
  3. 扩展性:如果需要在未来添加新功能或字段,遵循一致的协议可以更容易地进行扩展。

五、具体示例解析

1. 前端发送初始化消息
javascript 复制代码
socket.send(JSON.stringify({ 
    "message": "Hello, server!", 
    "flow_id": flow_id, 
    "chat_id": chat_id 
}));
  • message:实际的聊天内容。
  • flow_idchat_id:用于标识会话和流,确保后端能够将消息正确路由到相应的处理逻辑。
2. 后端接收并处理消息
python 复制代码
async def handle_websocket(
        self,
        flow_id: str,
        chat_id: str,
        websocket: WebSocket,
        user_id: int,
        gragh_data: dict = None,
):
    await self.connect(flow_id, chat_id, websocket)
    try:
        while True:
            try:
                json_payload_receive = await asyncio.wait_for(websocket.receive_json(), timeout=2.0)
            except asyncio.TimeoutError:
                json_payload_receive = ''
            payload = json.loads(json_payload_receive) if json_payload_receive else {}
            await chat_client.handle_message(payload)
    except WebSocketDisconnect as e:
        logger.info('Client disconnected: {}'.format(e))
    except Exception as e:
        logger.exception(e)
        await self.close_client(client_key, code=status.WS_1011_INTERNAL_ERROR, reason='Internal Error')
    finally:
        await self.close_client(client_key, code=status.WS_1000_NORMAL_CLOSURE, reason='Client disconnected')
  • 接收消息websocket.receive_json() 接收前端发送的 JSON 消息,并解析为 payload
  • 处理消息 :调用 chat_client.handle_message(payload) 处理消息逻辑。
  • 发送响应 :在 handle_message 中,使用 send_jsonsend_message 方法将响应发送回前端。
3. 后端发送响应
python 复制代码
async def send_json(self, client_id: str, chat_id: str, message: ChatMessage, add=True):
    message.flow_id = client_id
    message.chat_id = chat_id
    websocket = self.active_connections[get_cache_key(client_id, chat_id)]
    if add:
        self.chat_history.add_message(client_id, chat_id, message)
    await websocket.send_json(message.dict())
  • 设置消息字段 :将 client_idchat_id 添加到消息中。
  • 记录聊天历史 :如果 addTrue,将消息记录到聊天历史中。
  • 发送消息 :通过 websocket.send_json 将消息发送给前端。

目录

  1. WebSocket 基础概念
  2. 项目结构概览
  3. 前端建立 WebSocket 连接
  4. 后端 WebSocket 端点处理
  5. 后端服务层处理 WebSocket 消息
  6. 消息传递流程详细解析
  7. 断开连接和错误处理
  8. 总结与建议

1. WebSocket 基础概念

WebSocket 是一种在客户端(通常是浏览器)和服务器之间建立持久化的全双工通信通道的协议。与传统的 HTTP 请求-响应模式不同,WebSocket 允许客户端和服务器在连接建立后随时互相发送数据,而无需每次交互都重新建立连接。这使得 WebSocket 特别适合实时应用,如聊天系统、实时通知、游戏等。

FastAPI 是一个现代、高性能的 Web 框架,支持 WebSocket。它允许你轻松地定义和管理 WebSocket 端点,并与异步编程模型无缝集成。

2. 项目结构概览

根据你提供的项目结构和代码片段,WebSocket 相关的代码主要分布在两个文件中:

  • API 层api/v1/chat.py
    负责定义 WebSocket 端点,并处理来自前端的连接请求。
  • 服务层chat/manager.py
    负责管理 WebSocket 连接、处理消息、维护聊天历史等核心逻辑。

3. 前端建立 WebSocket 连接

在 WebSocket 通信流程中,前端首先需要建立与后端的 WebSocket 连接。假设前端使用 JavaScript,连接代码可能如下:

javascript 复制代码
const flow_id = "example_flow_id"; // 流程ID
const chat_id = "example_chat_id"; // 聊天ID
const token = "your_jwt_token";    // JWT 认证令牌

// 建立 WebSocket 连接
const socket = new WebSocket(`ws://yourserver.com/api/v1/chat/${flow_id}?chat_id=${chat_id}&t=${token}`);

// 连接成功
socket.onopen = function(event) {
    console.log("WebSocket 连接已建立");
    // 可以发送初始化消息
    socket.send(JSON.stringify({ "message": "Hello, server!", "flow_id": flow_id, "chat_id": chat_id }));
};

// 接收消息
socket.onmessage = function(event) {
    const message = JSON.parse(event.data);
    console.log("收到消息:", message);
    // 在页面上显示消息
};

// 连接关闭
socket.onclose = function(event) {
    console.log("WebSocket 连接已关闭");
};

// 连接错误
socket.onerror = function(error) {
    console.error("WebSocket 错误:", error);
};

解释:

  1. 建立连接 :前端通过 WebSocket 构造函数指定后端的 WebSocket 端点(ws://yourserver.com/api/v1/chat/${flow_id}),并附带必要的查询参数(如 chat_id 和 JWT 认证令牌 t)。
  2. 事件处理
    • onopen:连接成功后触发,可以在此发送初始化消息。
    • onmessage:接收到后端发送的消息时触发,前端可以在此处理和显示消息。
    • oncloseonerror:处理连接关闭和错误事件。

4. 后端 WebSocket 端点处理

在后端,api/v1/chat.py 定义了 WebSocket 端点 /chat/{flow_id},负责接收前端的连接请求,并将其传递给服务层进行进一步处理。

4.1 定义 WebSocket 端点
python 复制代码
@router.websocket('/chat/{flow_id}')
async def chat(
        *,
        flow_id: str,
        websocket: WebSocket,
        t: Optional[str] = None,
        chat_id: Optional[str] = None,
        version_id: Optional[int] = None,
        Authorize: AuthJWT = Depends(),
):
    """Websocket endpoint for chat."""
    try:
        # 认证
        if t:
            Authorize.jwt_required(auth_from='websocket', token=t)
            Authorize._token = t
        else:
            Authorize.jwt_required(auth_from='websocket', websocket=websocket)
        login_user = await get_login_user(Authorize)
        user_id = login_user.user_id

        # 获取流数据
        if chat_id:
            with session_getter() as session:
                db_flow = session.get(Flow, flow_id)
            if not db_flow:
                await websocket.accept()
                message = '该技能已被删除'
                await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason=message)
            if db_flow.status != 2:
                await websocket.accept()
                message = '当前技能未上线,无法直接对话'
                await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason=message)
            graph_data = db_flow.data
        else:
            flow_data_key = 'flow_data_' + flow_id
            if version_id:
                flow_data_key = flow_data_key + '_' + str(version_id)
            if not flow_data_store.exists(flow_data_key) or str(
                    flow_data_store.hget(flow_data_key, 'status'),
                    'utf-8') != BuildStatus.SUCCESS.value:
                await websocket.accept()
                message = '当前编译没通过'
                await websocket.close(code=status.WS_1013_TRY_AGAIN_LATER, reason=message)
                return
            graph_data = json.loads(flow_data_store.hget(flow_data_key, 'graph_data'))

        if not chat_id:
            # 调试时,每次都初始化对象
            chat_manager.set_cache(get_cache_key(flow_id, chat_id), None)

        with logger.contextualize(trace_id=chat_id):
            logger.info('websocket_verify_ok begin=handle_websocket')
            await chat_manager.handle_websocket(flow_id,
                                                chat_id,
                                                websocket,
                                                user_id,
                                                gragh_data=graph_data)
    except WebSocketException as exc:
        logger.error(f'Websocket error: {str(exc)}')
        await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc))
    except Exception as exc:
        logger.exception(f'Error in chat websocket: {str(exc)}')
        messsage = exc.detail if isinstance(exc, HTTPException) else str(exc)
        if 'Could not validate credentials' in str(exc):
            await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason='Unauthorized')
        else:
            await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=messsage)

解释:

  1. 端点定义 :使用 @router.websocket('/chat/{flow_id}') 定义 WebSocket 端点,flow_id 是路径参数。
  2. 认证
    • 通过 JWT 令牌 t 或 WebSocket 的认证机制验证用户身份。
    • 使用 Authorize.jwt_required 进行认证,确保只有合法用户可以建立连接。
  3. 获取流数据
    • 如果 chat_id 存在,表示这是一个已有的聊天会话,后端从数据库中获取对应的 Flow 数据。
    • 如果 chat_id 不存在,则检查 flow_data_store(Redis)中是否存在编译通过的流数据。如果不存在或状态不为成功,关闭连接并返回错误。
  4. 初始化聊天管理器
    • 如果没有 chat_id,则调用 chat_manager.set_cache 初始化聊天缓存。
  5. 调用服务层处理 WebSocket
    • 使用 await chat_manager.handle_websocket(...) 将 WebSocket 连接交给服务层 (ChatManager) 处理。
  6. 异常处理
    • 捕获 WebSocketException 和其他异常,记录日志并适当地关闭 WebSocket 连接。
4.2 连接建立逻辑

当前端发起 WebSocket 连接时,后端会执行以下步骤:

  1. 认证用户:确保连接请求来自合法用户。
  2. 验证流数据 :检查 flow_id 是否有效,确保相关技能已上线。
  3. 初始化连接 :将连接添加到 ChatManager 的活动连接列表中。
  4. 转发处理:将 WebSocket 连接的后续消息处理交给服务层。

5. 后端服务层处理 WebSocket 消息

服务层代码 chat/manager.py 中的 ChatManager 类负责具体的 WebSocket 消息处理和连接管理。我们将重点关注与 WebSocket 通信相关的部分,特别是 handle_websocket 函数。

5.1 ChatManager 类概览
python 复制代码
class ChatManager:

    def __init__(self):
        self.active_connections: Dict[str, WebSocket] = {}
        self.chat_history = ChatHistory()
        self.cache_manager = cache_manager
        self.cache_manager.attach(self.update)
        self.in_memory_cache = InMemoryCache()
        self.task_manager: List[asyncio.Task] = []
        self.active_clients: Dict[str, ChatClient] = {}
        self.stream_queue: Dict[str, Queue] = {}

解释:

  • active_connections :存储当前活跃的 WebSocket 连接,键为 client_idchat_id 的组合键。
  • chat_history:维护聊天历史记录。
  • cache_managerin_memory_cache:管理缓存数据,提升性能。
  • active_clients:存储已连接的客户端信息。
  • stream_queue:用于处理流式消息的队列。
5.2 handle_websocket 函数详解
python 复制代码
async def handle_websocket(
        self,
        flow_id: str,
        chat_id: str,
        websocket: WebSocket,
        user_id: int,
        gragh_data: dict = None,
):
    client_key = uuid.uuid4().hex
    chat_client = ChatClient(...)
    await self.accept_client(client_key, chat_client, websocket)
    try:
        while True:
            try:
                json_payload_receive = await asyncio.wait_for(websocket.receive_json(), timeout=2.0)
            except asyncio.TimeoutError:
                json_payload_receive = ''
            payload = json.loads(json_payload_receive) if json_payload_receive else {}
            await chat_client.handle_message(payload)
    except WebSocketDisconnect as e:
        logger.info('Client disconnected: {}'.format(e))
    except Exception as e:
        logger.exception(e)
        await self.close_client(client_key, code=status.WS_1011_INTERNAL_ERROR, reason='Internal Error')
    finally:
        await self.close_client(client_key, code=status.WS_1000_NORMAL_CLOSURE, reason='Client disconnected')

解释:

  1. 接受客户端连接
    • 生成唯一的 client_key
    • 创建 ChatClient 实例,代表一个具体的客户端。
    • 调用 accept_client 方法将客户端连接加入 active_clients
  2. 消息接收循环
    • 使用 while True 进入循环,持续接收来自客户端的消息。
    • 使用 asyncio.wait_for 设置接收消息的超时时间为 2 秒,避免长时间阻塞。
    • 如果接收到消息,解析为 payload 并调用 chat_client.handle_message(payload) 处理消息。
  3. 异常处理
    • WebSocketDisconnect:客户端断开连接时,记录日志。
    • 其他异常:捕获并记录异常,关闭连接。
  4. 资源清理
    • finally 块中,确保无论发生何种情况,连接都能被正确关闭,并释放相关资源。

6. 消息传递流程详细解析

为了更清晰地理解前端与后端之间的 WebSocket 通信流程,下面将结合前面介绍的两个文件中的关键代码,逐步解析消息从前端到后端再返回前端的完整流程。

6.1 前端发送消息

假设前端通过 WebSocket 连接后,发送一条消息:

javascript 复制代码
socket.send(JSON.stringify({ "message": "Hello, server!", "flow_id": "flow_id", "chat_id": "chat_id" }));

解释:

  • 消息内容 :包含 message(实际内容)、flow_idchat_id
  • 发送方式 :通过 WebSocket 的 send 方法发送 JSON 格式的消息。
6.2 后端接收消息
  1. API 层接收连接请求
    • 前端连接到 /chat/{flow_id},后端 chat 端点接收到连接请求。
    • 后端完成认证和流数据验证后,将连接交给 ChatManager 进行处理。
  2. 服务层管理连接
    • ChatManager.handle_websocket 接收到连接,初始化客户端处理器 ChatClient
    • 开始消息接收循环,等待前端发送的消息。
  3. 接收并处理消息
    • 前端发送的消息通过 websocket.receive_json() 被后端接收并解析为 payload
    • ChatClient.handle_message(payload) 被调用,负责具体的业务逻辑处理。
6.3 业务逻辑处理

ChatClient.handle_message(payload) 中,可能会执行以下操作(具体实现取决于 ChatClient 的定义,但根据项目常见模式,可以做如下假设):

  1. 解析消息:提取消息内容和相关参数。
  2. 业务逻辑处理:根据消息内容调用相应的服务或处理函数,如查询数据库、调用语言模型生成回复等。
  3. 生成响应:创建一个响应消息对象,准备发送回前端。
6.4 发送响应消息
  1. 服务层发送消息:
    • 处理完消息后,服务层使用 ChatManager.send_jsonChatManager.send_message 方法将响应发送回前端。
python 复制代码
async def send_json(self, client_id: str, chat_id: str, message: ChatMessage, add=True):
    message.flow_id = client_id
    message.chat_id = chat_id
    websocket = self.active_connections[get_cache_key(client_id, chat_id)]
    if add:
        self.chat_history.add_message(client_id, chat_id, message)
    await websocket.send_json(message.dict())

解释:

  • 参数
    • client_idchat_id:用于查找对应的 WebSocket 连接。
    • message:要发送的消息对象,通常为 ChatMessage 类型。
    • add:是否将消息记录到聊天历史中。
  • 流程
    1. client_idchat_id 添加到消息中。
    2. 查找对应的 WebSocket 连接。
    3. 如果 addTrue,将消息添加到聊天历史记录。
    4. 通过 websocket.send_json 方法将消息以 JSON 格式发送给前端。
  1. 前端接收响应
javascript 复制代码
socket.onmessage = function(event) {
    const message = JSON.parse(event.data);
    console.log("收到消息:", message);
    // 在页面上显示消息
};

解释:

  • 前端的 onmessage 事件处理函数接收到后端发送的 JSON 消息后,解析并处理显示。

7. 断开连接和错误处理

在 WebSocket 通信过程中,连接可能会因为各种原因断开,如用户关闭浏览器、网络问题或服务器错误。后端需要妥善处理这些情况,确保资源被正确释放,避免内存泄漏或其他问题。

7.1 客户端断开连接

当客户端主动断开 WebSocket 连接时,后端 ChatManager.handle_websocket 会捕获 WebSocketDisconnect 异常:

python 复制代码
except WebSocketDisconnect as e:
    logger.info('Client disconnected: {}'.format(e))

解释:

  • 记录断开连接的日志,便于后续调试和监控。
7.2 后端主动关闭连接

后端在检测到某些错误或异常情况下,可以主动关闭 WebSocket 连接:

python 复制代码
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason=message)

解释:

  • code:WebSocket 关闭代码,表明连接关闭的原因。
  • reason:具体的关闭原因,便于前端理解和处理。
7.3 异常处理

在消息处理过程中,可能会发生各种异常,后端需要捕获并处理:

python 复制代码
except Exception as exc:
    logger.exception(str(exc))
    await self.close_connection(flow_id=flow_id,
                                chat_id=chat_id,
                                code=status.WS_1011_INTERNAL_ERROR,
                                reason='后端未知错误类型',
                                key_list=key_list)

解释:

  • 记录异常:使用日志记录详细的错误信息,便于调试。
  • 关闭连接 :通过 close_connection 方法关闭 WebSocket 连接,确保资源被释放。
7.4 资源清理

finally 块中,确保所有连接和任务被正确清理:

python 复制代码
finally:
    thread_pool.cancel_task(key_list)  # 取消进行中的任务
    await self.close_connection(flow_id=flow_id,
                                chat_id=chat_id,
                                code=status.WS_1000_NORMAL_CLOSURE,
                                reason='Client disconnected',
                                key_list=key_list)
    self.disconnect(flow_id, chat_id)

解释:

  • 取消任务:确保所有与连接相关的后台任务被取消,避免资源泄漏。
  • 关闭连接 :调用 close_connection 方法关闭 WebSocket 连接。
  • 断开连接 :从 active_connections 中移除连接,释放资源。

8. 总结与建议

通过上述解析,你应该对项目中 WebSocket 的整体通信流程有了清晰的理解。以下是一些关键点和建议,帮助你更好地掌握和应用 WebSocket 技术:

  1. 理解 WebSocket 基础:熟悉 WebSocket 的基本概念、工作原理以及与 HTTP 的区别。了解全双工通信和持久连接的优势。
  2. 熟悉 FastAPI 的 WebSocket 功能
    • 学习 FastAPI 如何定义和管理 WebSocket 端点。
    • 理解 WebSocket 对象的方法,如 accept(), send_text(), send_json(), receive_text(), receive_json(), close() 等。
  3. 异步编程
    • WebSocket 通信通常涉及大量并发连接和异步操作,熟练掌握 asyncawait 关键字,理解 asyncio 的基本概念。
  4. 连接管理
    • 使用合适的数据结构(如字典)管理活跃的 WebSocket 连接,确保能够快速查找和发送消息。
    • 实现连接的建立、维护和断开机制,确保资源被正确管理。
  5. 消息处理
    • 定义清晰的消息协议,确保前后端之间的数据格式一致。
    • 在服务层处理具体的业务逻辑,保持 API 层的简洁。
  6. 错误处理与资源清理
    • 捕获和处理各种可能的异常,确保 WebSocket 连接能够在异常情况下被正确关闭。
    • 在连接断开或发生错误时,确保所有相关资源被释放,避免内存泄漏。
  7. 安全性
    • 在建立 WebSocket 连接时,进行身份验证和授权,确保只有合法用户可以连接和发送消息。
    • 处理潜在的安全漏洞,如消息注入、拒绝服务攻击等。
  8. 调试与日志记录
    • 使用日志记录关键事件和错误信息,帮助调试和监控 WebSocket 连接的状态。
    • 定期检查日志,识别和解决潜在问题。

示例流程图

为了更直观地理解 WebSocket 通信流程,下面是一个简化的流程图:

前端                  后端 API 层 (`api/v1/chat.py`)           服务层 (`chat/manager.py`)
  |                            |                                     |
  | --建立 WebSocket 连接-----> |                                     |
  |                            | --认证和验证流数据-------------->  |
  |                            |                                     | --添加到 active_connections
  |                            | <----------连接成功/失败----------- |
  | --发送消息(JSON)----------> |                                     |
  |                            | --转发消息到 ChatManager          |
  |                            |                                     | --处理消息逻辑
  |                            |                                     | --生成响应
  |                            | <---------发送响应消息------------ |
  | <--------接收响应消息-------- |                                     |
  |                            |                                     |
  | --断开连接------------------> |                                     |
  |                            | --处理断开连接和资源清理---------->  |
  |                            |                                     | --移除连接
  |                            | <---------断开连接确认----------- |

示例流程图的详细优化:

  1. 用户提交申请 (Client -> Web Server)

    • 数据格式: HTTP POST 请求,内容为 JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "user_id": "12345",
        "application_type": "loan",
        "amount": 10000,
        "submission_date": "2024-12-04"
      }
  2. Web Server 验证数据完整性与格式 (Web Server)

    • 检查项:
      • user_id 是否存在且格式正确。
      • application_type 是否有效(例如,"loan")。
      • amount 是否为数字且符合申请的业务规则。
    • 响应:
      • 如果验证失败,返回 400 错误,并说明错误原因。
      • 如果验证成功,将数据传递给下一步服务。
  3. Web Server 转发数据到认证服务 (Web Server -> Authentication Service)

    • 数据格式: HTTP POST 请求,内容为 JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "user_id": "12345",
        "application_type": "loan",
        "amount": 10000
      }
    • 认证服务逻辑:

      • 校验 user_id 是否有效,检查用户是否符合资格(如年龄、信用评分等)。
      • 通过数据库或外部 API 检查用户状态。
  4. 认证服务返回认证结果 (Authentication Service -> Web Server)

    • 数据格式: HTTP 响应,JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "user_id": "12345",
        "status": "approved",  // 或 "rejected"
        "reason": "User meets credit criteria"
      }
    • 处理:

      • 如果认证失败(例如,信用评分不足),status 为 "rejected"。
      • 如果认证成功,status 为 "approved",并传递给业务逻辑处理层。
  5. Web Server 转发数据到业务逻辑服务 (Web Server -> Business Logic Service)

    • 数据格式: HTTP POST 请求,内容为 JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "user_id": "12345",
        "status": "approved",
        "amount": 10000,
        "submission_date": "2024-12-04"
      }
    • 业务逻辑:

      • 进行更复杂的业务逻辑,例如对 amount 进行规则校验、计算利息、生成合同内容等。
  6. 业务逻辑服务返回处理结果 (Business Logic Service -> Web Server)

    • 数据格式: HTTP 响应,JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "application_id": "67890",
        "user_id": "12345",
        "loan_amount": 10000,
        "status": "approved",
        "loan_terms": {
          "interest_rate": 5.5,
          "duration_months": 12
        },
        "approval_date": "2024-12-04"
      }
    • 处理:

      • 如果业务逻辑成功,生成申请 ID,返回申请详情。
      • 如果失败(例如,金额不符或条件不满足),返回失败的具体原因。
  7. Web Server 提交数据到第三方支付/账户服务 (Web Server -> Payment Service)

    • 数据格式: HTTP POST 请求,内容为 JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "user_id": "12345",
        "loan_id": "67890",
        "loan_amount": 10000,
        "payment_method": "bank_transfer",
        "account_details": {
          "account_number": "987654321",
          "bank_name": "ABC Bank"
        }
      }
    • 支付服务:

      • 根据贷款信息和用户的账户信息,处理资金发放流程。
  8. 支付服务返回支付结果 (Payment Service -> Web Server)

    • 数据格式: HTTP 响应,JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "loan_id": "67890",
        "payment_status": "success",  // 或 "failure"
        "payment_date": "2024-12-05",
        "transaction_id": "TX123456789"
      }
    • 处理:

      • 如果支付成功,返回成功信息及支付凭证。
      • 如果支付失败,返回失败原因和错误代码。
  9. Web Server 返回最终响应给用户 (Web Server -> Client)

    • 数据格式: HTTP 响应,JSON 格式。

    • 数据内容:

      json 复制代码
      {
        "user_id": "12345",
        "application_id": "67890",
        "loan_status": "approved",
        "payment_status": "success",
        "loan_terms": {
          "interest_rate": 5.5,
          "duration_months": 12
        },
        "transaction_id": "TX123456789",
        "message": "Your loan application has been successfully processed."
      }

相关推荐
wellnw11 分钟前
[Router]路由器常用的后台判断网络ping 可靠公共 IP 地址整理
网络
廿二又12 分钟前
http 请求总结get
网络·网络协议·http
Vin0sen15 分钟前
xiaomiR4c openwrt
网络
是小崔啊21 分钟前
开源轮子 - HTTP Client组件
网络协议·http·开源
亚远景aspice35 分钟前
亚远景-ISO 21434标准下的汽车网络安全测试:全面要求与实施策略
网络·web安全·汽车
忘川8561 小时前
以太网帧结构
网络·物联网·网络协议
IPdodo全球网络服务1 小时前
如何通过TikTok引流到私域流量池
运维·服务器·网络
莫固执,朋友1 小时前
Linux下编译 libwebsockets简介和使用示例
linux·websocket·音视频
手心里的白日梦1 小时前
网络层协议--ip协议
网络·网络协议·tcp/ip
IT 古月方源2 小时前
关于高级acl的配置和讲解
运维·开发语言·网络·tcp/ip·智能路由器