| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- ---
- description: Go WebSocket 服务开发规范
- globs: ["**/*.go"]
- alwaysApply: true
- ---
- # Go WebSocket 服务开发核心规范
- ## 1. 技术选型与库使用
- - **首选库**: 本项目统一使用 `github.com/gorilla/websocket` 库来处理 WebSocket 连接。
- - **禁止使用**: 除非有特殊理由,请**避免**直接使用标准库 `golang.org/x/net/websocket`,因为它缺少一些高级功能和性能优化。
- ## 2. WebSocket 连接处理
- - **Upgrader 配置**:
- - 必须创建一个全局或可重用的 `websocket.Upgrader` 实例。
- - `CheckOrigin` 函数**必须**实现,用于校验请求来源,防止跨站 WebSocket 劫持 (CSWSH)。在开发环境中可以暂时允许所有来源,但在生产环境中必须严格校验。
- ```go
- var upgrader = websocket.Upgrader{
- ReadBufferSize: 1024,
- WriteBufferSize: 1024,
- CheckOrigin: func(r *http.Request) bool {
- // TODO: 在生产环境中替换为你的域名白名单
- // return r.Header.Get("Origin") == "[https://yourdomain.com](https://yourdomain.com)"
- return true // 开发环境
- },
- }
- ```
- - **连接升级**: 在 HTTP Handler 中,使用 `upgrader.Upgrade(w, r, nil)` 来将会话升级为 WebSocket 连接。务必妥善处理该过程中的 `error`。
- - **并发安全**: `websocket.Conn` 对象**不是**并发安全的。对同一个连接的写操作必须在单一的 goroutine 中进行。通常的设计模式是为每个连接启动两个 goroutine:一个用于读(`ReadMessage`),一个用于写。
- ## 3. 设计模式与代码结构
- - **核心结构体**:
- - **Client/Connection**: 创建一个结构体来封装 `*websocket.Conn`,并包含其他与客户端相关的状态,如用户ID、订阅的频道等。
- ```go
- type Client struct {
- conn *websocket.Conn
- send chan []byte // 用于发送消息的缓冲 channel
- // 其他用户标识...
- userID string
- }
- ```
- - **Hub/Manager**: 创建一个中心化的管理器,用于处理客户端的注册、注销和消息广播。
- ```go
- type Hub struct {
- clients map[*Client]bool
- broadcast chan []byte
- register chan *Client
- unregister chan *Client
- }
- ```
- - **读写分离**:
- - **读 Goroutine (`readPump`)**:
- - 在一个 `for` 循环中持续调用 `conn.ReadMessage()`。
- - 在此 goroutine 中处理连接关闭和错误。当 `ReadMessage` 返回错误时,意味着客户端已断开,应执行清理逻辑(如调用 `hub.unregister`)。
- - 设置 Pong 消息处理器,用于维持心跳。
- - 设置读超时 `conn.SetReadDeadline()`。
- - **写 Goroutine (`writePump`)**:
- - 从 `Client` 的 `send` channel 中读取消息。
- - 在一个 `for` 循环中使用 `conn.WriteMessage()` 发送消息。
- - 设置 Ping 消息,定期发送以检测连接活性。
- - 设置写超时 `conn.SetWriteDeadline()`。
- ## 4. 消息格式
- - **统一格式**: 所有客户端与服务端之间的消息都应使用 JSON 格式。
- - **消息结构**: 定义一个标准的消息结构体,包含消息类型、荷载 (payload) 等字段,以便于路由和处理。
- ```go
- type WebSocketMessage struct {
- Type string `json:"type"`
- Payload interface{} `json:"payload"`
- }
|