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
相关产品推荐
相关产品推荐

