Go标准库无WebSocket支持,应选用gorilla/websocket;golang.org/x/net/websocket已弃用且不兼容RFC 6455,易致400错误;服务端需正确配置Upgrader.CheckOrigin、设读写Deadline;广播宜用sync.Map存连接+每连接双goroutine+带缓冲chan;Nginx须配置proxy_http_version 1.1、Upgrade和Connection头及长read_timeout。

Go 标准库不提供 WebSocket 支持,必须用第三方库;gorilla/websocket 是当前最稳定、文档最全、生产环境验证最多的选项,别选错。
为什么不用 golang.org/x/net/websocket
这个包早已被官方标记为 Deprecated,最后一次更新是 2017 年,不支持 RFC 6455 完整握手流程,遇到 Nginx 反向代理或现代浏览器(如 Chrome 90+)会直接报 400 Bad Request 或连接立即关闭。它连 Sec-WebSocket-Accept 校验都可能出错。
实际开发中你只会看到两种错误:
-
websocket: bad handshake(服务端返回头缺失或格式错) - 浏览器控制台显示
Failed to construct 'WebSocket': The subprotocol is invalid.
gorilla/websocket 的基础服务端写法
核心是用 upgrader.Upgrade() 把 HTTP 连接“升级”为 WebSocket,之后所有通信走 *websocket.Conn。
立即学习“go语言免费学习笔记(深入)”;
关键点:
-
Upgrader.CheckOrigin必须显式设置,否则默认只允许同源,跨域请求直接 403 - 不要在
http.HandlerFunc里做耗时操作(比如数据库查询),升级前应尽量轻量 -
conn.SetReadDeadline()和conn.SetWriteDeadline()建议设,否则长连接可能因网络波动卡死
示例片段:
本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。 本书内容全面深入,适合各层次PHP和MySQL开发人员阅读,既是优秀的学习教程,也可用作参考手册。
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // 生产环境请按需校验 Origin
},
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade error:", err)
return
}
defer conn.Close()
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Println("read error:", err)
break
}
if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
log.Println("write error:", err)
break
}
}
}
如何安全地广播消息给多个客户端
别用全局 map + mutex 粗暴管理连接——并发读写 map 会 panic;也别每个连接起 goroutine 循环 ReadMessage 后再发到公共 channel,容易堆积阻塞。
推荐做法是:每个连接一个读 goroutine + 一个写 goroutine,用带缓冲的 chan []byte 做消息队列,写 goroutine 负责串行发送。
- 广播时遍历所有活跃连接,向各自
sendchannel 发送消息(非阻塞写) - 连接断开时记得 close channel,避免写 goroutine 永久阻塞
- 用
sync.Map存连接(key 用自增 ID 或 session ID),比普通 map + mutex 更适合高频增删
真正容易翻车的是:忘记调用 conn.Close() 或没处理 websocket.CloseMessage,导致连接泄漏,fd 耗尽后新连接全部失败。
Nginx 配置 WebSocket 的几个硬性要求
Nginx 默认不透传 Upgrade 请求,必须显式开启。漏掉任意一项,前端就卡在 CONNECTING 状态。
-
proxy_http_version 1.1;(必须是 1.1,1.0 不支持 Upgrade) -
proxy_set_header Upgrade $http_upgrade;(大小写敏感,$http_upgrade 是 nginx 内置变量) -
proxy_set_header Connection "upgrade";(值必须是"upgrade"字符串,不能是$http_connection) -
proxy_read_timeout 86400;(设大一点,避免空闲超时断连)
如果用 Let’s Encrypt + HTTPS,还要确认证书链完整,否则 iOS Safari 会静默拒绝 WebSocket 连接,无任何错误提示。









