用 gorilla/websocket 连 websocket 服务最稳,它是生产环境事实标准;需传完整 url、手动设超时与 deadline、正确处理 close 帧,避免 dns、tls、代理、心跳及编码问题。

用 gorilla/websocket 连 WebSocket 服务最稳
Go 官方标准库不带 WebSocket 客户端,硬要用 net/http 自己拼协议容易出错。生产环境基本都用 gorilla/websocket——它不是“可选”,是事实标准。
别碰 gobwas/ws 或其他小众包,握手兼容性差、TLS 错误处理弱,连某些 Nginx 代理后的服务都会静默失败。
- 安装:
go get github.com/gorilla/websocket - 连接时必须传完整 URL(含
wss://或ws://),不能只传域名或路径 - 如果服务端启用了 JWT 鉴权,得把 token 放在
Origin头里(部分网关要求)或用websocket.Dialer的Proxy和TLSClientConfig手动设Header
连接失败常见报错和对应解法
dial tcp: lookup example.com: no such host —— DNS 解析失败,检查 http.DefaultClient 是否被污染,或本地 /etc/hosts 写错;tls: first record does not look like a TLS handshake —— 误用 wss:// 连了没开 TLS 的服务端,换 ws://。
- 超时默认是 0(无限),务必手动设
websocket.Dialer{Timeout: 5 * time.Second} - 遇到
bad status报错,大概率是服务端返回了非101 Switching Protocols,比如反向代理返回了 403/404,用curl -i http://host/path先确认 HTTP 层通不通 - 如果走公司内网或代理,
Dialer.Proxy要显式设为http.ProxyFromEnvironment,否则会直连失败
读写数据时别卡死在 ReadMessage 或 WriteMessage
这两个函数是阻塞的,没加超时或没配好 SetReadDeadline / SetWriteDeadline,一次网络抖动就让 goroutine 永久挂起。
- 每次
conn.ReadMessage()前必须调conn.SetReadDeadline(time.Now().Add(10 * time.Second)) - 发心跳别用
time.Ticker直接WriteMessage,先用select+default判断 conn 是否还活着,否则可能 panic:「use of closed network connection」 - 接收二进制消息用
websocket.BinaryMessage类型,别用TextMessage强转,中文会乱码
关闭连接前必须发 CloseMessage 并等对方响应
直接 conn.Close() 是粗暴断连,服务端收不到关闭帧,可能长时间保留连接,触发连接数限制或心跳超时下线。
- 正确流程:
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))→conn.SetReadDeadline(time.Now().Add(3 * time.Second))→conn.ReadMessage()(吃掉服务端回的 close 帧)→conn.Close() - 如果 ReadMessage 超时,说明服务端已断开,直接 Close 即可,不用强求响应
- 注意
websocket.CloseAbnormalClosure和CloseGoingAway语义不同,前者表示客户端异常退出,后者是主动下线,服务端行为可能不一样
WebSocket 不是“连上就能发”,每个环节都依赖状态同步。最容易漏的是 deadline 设置和 close 帧交互——这两处一错,问题往往出现在上线后半夜三点。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











