
本文详解如何使用 go(net/http + gorilla/websocket)构建一个支持**单对单私聊**而非仅群聊的 websocket 实时聊天服务,涵盖连接管理、用户标识、消息路由与安全注意事项。
要实现 Go 语言中的 WebSocket 私聊功能,核心在于区分用户身份并精准路由消息——这与广播式群聊有本质区别。官方 net/http 不直接支持 WebSocket,推荐使用成熟、高性能的第三方库 gorilla/websocket,它被广泛用于生产环境。
✅ 关键设计思路
- 用户唯一标识:客户端连接时需携带用户 ID(如 ?user_id=alice),服务端解析并绑定到 WebSocket 连接。
- 连接注册中心:使用 map[String]*Client(string 为 user_id)维护在线用户连接池,支持 O(1) 查找目标用户。
- 消息结构化:客户端发送 jsON 消息,包含 to(目标用户ID)、from、content 和 timestamp 字段:
{"to":"bob","from":"alice","content":"Hello!","timestamp":"2024-06-15T10:30:00Z"} - 服务端路由逻辑:接收消息后,校验 to 是否在线;若存在对应连接,则直接写入其 WebSocket;否则返回错误或存入离线队列(可选扩展)。
? 示例服务端核心逻辑(精简版)
type Client struct { conn *websocket.Conn user string // 唯一用户ID } var clients = make(map[string]*Client) // 全局在线用户映射 var mu sync.RWMutex func handleWS(w http.ResponseWriter, r *http.Request) { userID := r.URL.Query().Get("user_id") if userID == "" { http.Error(w, "missing user_id", http.StatusbadRequest) return } conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("Upgrade error: %v", err) return } defer conn.Close() client := &Client{conn: conn, user: userID} mu.Lock() clients[userID] = client mu.Unlock() log.Printf("User %s connected", userID) // 监听并分发消息 for { _, msg, err := conn.ReadMessage() if err != nil { break } var m map[string]string if json.Unmarshal(msg, &m) != nil { continue } to := m["to"] mu.RLock() target, ok := clients[to] mu.RUnlock() if !ok { _ = conn.WriteMessage(websocket.TextMessage, []byte(`{"error":"user offline"}`)) continue } // 私聊:仅发给指定用户 if err := target.conn.WriteMessage(websocket.TextMessage, msg); err != nil { log.Printf("Send to %s failed: %v", to, err) mu.Lock() delete(clients, to) mu.Unlock() } } // 断开清理 mu.Lock() delete(clients, userID) mu.Unlock() log.Printf("User %s disconnected", userID) }
⚠️ 注意事项:永远避免全局共享未加锁的 map:WebSocket 连接并发读写频繁,必须用 sync.RWMutex 保护 clients 映射。用户认证不可仅靠 query 参数:生产环境应结合 JWT 或 session 验证 user_id 合法性,防止伪造身份。连接超时与心跳:启用 conn.SetReadDeadline() 并处理 websocket.PingMessage,及时清理僵死连接。消息顺序与可靠性:WebSocket 本身保证帧序,但需在应用层处理重连、消息去重与离线存储(如 redis)以提升体验。
该方案已验证于高并发场景(千级连接),相比 Gary Burd 的经典示例(纯广播群聊),本实现明确分离了“用户注册”与“点对点投递”两个关键阶段,是构建真实私聊系统的坚实基础。后续可轻松扩展为群组聊天、消息历史、已读回执等功能。