gorilla/websocket 是当前 go 生态最稳定、文档最全、社区支持最好的 websocket 实现库,而 golang.org/x/net/websocket 已弃用且不兼容 rfc 6455,会导致握手失败;upgrader 必须配置 checkorigin 防跨域拒绝;读写需分离 goroutine 并设超时;广播用 map + sync.rwmutex 而非 sync.map;需主动清理断连避免内存泄漏。

gorilla/websocket 是当前 Go 生态中最稳定、文档最全、社区支持最好的 WebSocket 实现库,golang.org/x/net/websocket 已基本弃用(自 Go 1.18 起不再维护),且无法处理现代浏览器的 Sec-WebSocket-Key 验证,直接用会导致 websocket: bad handshake 错误。
为什么不能用 golang.org/x/net/websocket
说明:该包早在 2019 年就进入只修复严重 bug 的维护模式,2023 年后彻底停止更新。它不支持子协议协商、缺少心跳机制、无法正确解析 Sec-WebSocket-Version: 13,在 Chrome/Firefox 最新版中握手必然失败。
- 错误现象:
websocket: bad handshake或连接立即关闭,无日志提示 - 真实原因:服务端返回的
Sec-WebSocket-Accept计算逻辑过时,与 RFC 6455 不兼容 - 兼容性影响:即使本地测试“看似能通”,上线后在任意公网环境(Nginx、CDN、iOS Safari)都会出问题
gorilla/websocket 的 Upgrader 必须配置 CheckOrigin
说明:默认情况下,Upgrader 会拒绝所有跨域请求,前端页面从 http://localhost:3000 连接 ws://localhost:8080 就会失败,报错 websocket: origin not allowed。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 开发阶段可临时设为
func(r *http.Request) bool { return true } - 生产环境必须校验 Origin 域名,例如:
strings.HasSuffix(r.Header.Get("Origin"), "myapp.com") - 切勿在
CheckOrigin中写死http://localhost:3000—— 浏览器会把端口也当作 Origin 一部分,但移动端 WebView 或 Electron 可能无 Origin 头,需额外判断
消息读写必须分离 goroutine,否则会阻塞连接
说明:conn.ReadMessage() 和 conn.WriteMessage() 都是阻塞调用。如果在同一个 goroutine 里交替读写,客户端发两个消息之间稍有延迟,服务端就会卡住,后续所有消息堆积,最终触发 write deadline exceeded。
- 正确做法:启动两个 goroutine ——
readPump专责读、writePump专责写,通过client.sendchannel 通信 - 必须设置读写超时:
conn.SetReadDeadline和conn.SetWriteDeadline,否则空闲连接永不释放 - 常见坑:
defer conn.Close()放在 handler 开头 —— 它会在函数退出时关闭,但 read/write goroutine 还在跑,导致 panic: “use of closed network connection”
广播消息要用 map + sync.RWMutex,别直接遍历 map
说明:并发读写原生 map 会 panic:fatal error: concurrent map iteration and map write。即使只读也要加锁,因为 Go runtime 检测到迭代时有写操作就直接崩溃。
- 安全做法:用
sync.RWMutex包裹 map,读用RLock()/RUnlock(),写用Lock()/Unlock() - 不要用
sync.Map—— 它适合 key 极多、读远多于写的场景(如百万级在线用户),普通聊天室用map+RWMutex更清晰、更易调试 - 广播前检查
conn.RemoteAddr()是否为空,避免已断开连接被遗漏清理,造成内存泄漏
readPump 的错误重试逻辑、writePump 的 channel 缓冲大小、以及每次 WriteMessage 后是否 conn.SetWriteDeadline 的时机里。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










