WebSocket服务端连不上需显式调用websocket.Upgrader.Upgrade,禁用http.Server读写超时,监听0.0.0.0而非localhost,使用gorilla/websocket并正确配置Nginx代理头。

WebSocket 服务端启动后连不上,net/http 路由没生效?
Go 的 http.Serve 默认不支持 WebSocket 升级,直接用 http.HandleFunc 注册路径不会自动处理 Upgrade 请求头。必须显式调用 websocket.Upgrader.Upgrade,否则浏览器会卡在 pending 或返回 400/500。
- 确保用
http.HandlerFunc包裹升级逻辑,别只写业务逻辑函数 -
Upgrader实例要复用,不要每次请求都 new —— 它带状态(比如检查 origin 的回调) - 常见错误:漏掉
w.Header().Set("Connection", "upgrade")—— 实际不用手动设,Upgrade方法内部已处理,手设反而可能冲突
用 gorilla/websocket 还是 golang.org/x/net/websocket?
后者早已被弃用(2016 年归档),文档缺失、无心跳支持、不兼容 HTTP/2 和现代 TLS 配置。所有新项目必须用 gorilla/websocket,它维护活跃、有完整测试、支持 SetReadDeadline 和 WriteMessage 等关键控制。
- 安装命令是
go get github.com/gorilla/websocket,不是x/net/websocket - 注意导入路径是
github.com/gorilla/websocket,不是gorilla/websocket(少github.com/会报错) - 它的
Upgrader.CheckOrigin默认拒绝非同源请求,开发时可临时设为func(r *http.Request) bool { return true },但上线前必须收紧
前端 new WebSocket("ws://localhost:8080/ws") 报错 ERR_CONNECTION_REFUSED?
不是代码问题,是服务根本没监听对应地址。Golang 默认绑定 localhost(即 127.0.0.1),而部分前端环境(如手机浏览器访问电脑 IP、Docker 容器内访问宿主)需要监听 0.0.0.0。
- 启动服务时用
http.ListenAndServe("0.0.0.0:8080", nil),别用"localhost:8080" - 如果用了反向代理(如 Nginx),确认它转发了
Upgrade和Connection头:proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade"; - Chrome 控制台 Network 标签页里点开 ws 请求,看 Headers → Request Headers 是否含
Sec-WebSocket-Key—— 没这个字段说明前端根本没发升级请求,可能是 URL 写成http://而非ws://
连接建立后秒断,read: connection reset by peer 或 i/o timeout?
WebSocket 是长连接,但 Go 默认的 http.Server 有 ReadTimeout 和 WriteTimeout,一旦设置就会强制关闭空闲连接。WebSocket 必须禁用这两个超时,改用 Conn.SetReadDeadline 在每次读前手动设。
立即学习“go语言免费学习笔记(深入)”;
- 在
http.Server初始化时明确设ReadTimeout: 0、WriteTimeout: 0(0 表示禁用) - 在
conn.ReadMessage前调用conn.SetReadDeadline(time.Now().Add(30 * time.Second)),否则默认无 deadline,但某些中间件或 NAT 网关会主动踢空闲连接 - 别依赖
http.Server.IdleTimeout来保活 —— 它只管 HTTP 连接空闲,不管 WebSocket 数据帧;心跳必须由应用层发Ping或业务消息
调试环境搭起来不难,难的是记住哪些超时该关、哪些头不能少、哪些包早该扔掉。尤其容易在本地跑通就以为万事大吉,一上测试机或配了 Nginx 就断连 —— 那些没显式暴露的网络边界,才是最常出问题的地方。










