You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IHP如何通过自定义Web Socket控制器实现客户端之间的数据收发?

IHP框架自定义WebSocket控制器实现群聊双向通信方案

需求说明

  • 基于IHP框架开发聊天应用,以服务器为中转节点实现多客户端双向通信
  • 触发逻辑:客户端发送请求到服务器,服务器完成数据更新后,主动向所有已连接的客户端推送最新响应消息
  • 原生Auto Refresh功能在当前场景下资源占用过高,因此采用自定义WebSocket方案实现

实现步骤

1. 创建自定义WebSocket控制器

新建Web/Controller/ChatSocket.hs文件,写入如下代码:

module Web.Controller.ChatSocket where

import Web.Controller.Prelude
import qualified Network.WebSockets as WS

instance Controller ChatSocketController where
    action MyChatSocketAction = do
        -- 从全局状态获取客户端连接池
        connectedClients <- getState @(IORef [WS.Connection])
        WS.sendTextData connection ("欢迎加入聊天" :: Text)
        -- 将新连接加入连接池
        modifyIORef' connectedClients (connection :)
        
        -- 持续监听当前客户端发送的消息
        forever $ do
            message <- WS.receiveData connection :: IO Text
            -- 业务逻辑处理:将消息持久化到数据库
            now <- getCurrentTime
            newMessage <- newRecord @ChatMessage
                |> set #content message
                |> set #createdAt now
                |> createRecord
            
            -- 广播新消息到所有已连接客户端
            clients <- readIORef connectedClients
            forM_ clients $ \client -> do
                WS.sendTextData client (tshow newMessage)

2. 注册WebSocket路由

在Web/Routes.hs中添加对应路由声明:

data ChatSocketController = MyChatSocketAction
    deriving (Eq, Show, Data)

instance HasPath ChatSocketController where
    pathTo MyChatSocketAction = "/chat-ws"

instance WebSocketsApp ChatSocketController where
    webSocketsApp = defaultWebSocketsApp @ChatSocketController

3. 初始化全局客户端连接池

在Web/FrontController.hs中初始化存储客户端连接的全局IORef:

instance InitControllerContext WebApplication where
    initContext = do
        connectedClients <- liftIO $ newIORef []
        putState connectedClients
        defaultInitContext

4. 前端对接WebSocket

添加前端JS逻辑完成连接、收消息、发消息能力:

// 建立WebSocket连接
const ws = new WebSocket('ws://' + window.location.host + '/chat-ws');

// 监听服务器推送的消息并渲染
ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    const messageElement = document.createElement('div');
    messageElement.textContent = message.content;
    document.getElementById('chat-container').appendChild(messageElement);
};

// 发送消息到服务器
function sendMessage() {
    const input = document.getElementById('message-input');
    const content = input.value.trim();
    if (content) {
        ws.send(content);
        input.value = '';
    }
}

优化说明

  • 需补充客户端断开连接时的连接池清理逻辑,避免无效连接堆积导致内存泄漏
  • 生产环境需增加消息序列化/反序列化校验,拦截非法数据
  • 可根据业务需要在WebSocket连接建立阶段添加用户鉴权逻辑,拦截未授权访问

内容的提问来源于stack exchange,提问作者Varun Rajput

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 14:24:04