Golang中Websocket连接快速关闭问题排查
Golang中Websocket连接快速关闭问题排查 我正在尝试这个WebSocket示例:
package main
import (
"fmt"
"log"
"net/http"
"golang.org/x/net/websocket"
)
func Echo(ws *websocket.Conn) {
var err error
for {
var reply string
if err = websocket.Message.Receive(ws, &reply); err != nil {
fmt.Println("Can't receive")
break
}
fmt.Println("Received back from client: " + reply)
msg := "Received: " + reply
fmt.Println("Sending to client: " + msg)
if err = websocket.Message.Send(ws, msg); err != nil {
fmt.Println("Can't send")
break
}
}
}
func main() {
http.Handle("/", websocket.Handler(Echo))
if err := http.ListenAndServe(":1234", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
使用这个客户端:
<html>
<head></head>
<body>
<script type="text/javascript">
var sock = null;
var wsuri = "ws://localhost:1234";
window.onload = function() {
console.log("onload");
sock = new WebSocket(wsuri);
sock.onopen = function() {
console.log("connected to " + wsuri);
}
sock.onclose = function(e) {
console.log("connection closed (" + e.code + ")");
}
sock.onmessage = function(e) {
console.log("message received: " + e.data);
}
};
function send() {
var msg = document.getElementById('message').value;
sock.send(msg);
};
</script>
<h1>WebSocket Echo Test</h1>
<form>
<p>
Message: <input id="message" type="text" value="Hello, world!">
</p>
</form>
<button onclick="send();">Send Message</button>
</body>
</html>
但是遇到了以下错误:

更多关于Golang中Websocket连接快速关闭问题排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我使用Firefox的WebSocket扩展测试了你的服务器代码,它运行正常,所以请检查你客户端的代码。
更多关于Golang中Websocket连接快速关闭问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Yamil_Bracho:
我测试了你的服务器代码
你检查的是哪一个,是原问题中使用 "golang.org/x/net/websocket" 的那个,还是使用 "nhooyr.io/websocket" 的那个?
日志显示连接失败。
你检查过 Echo 函数是否被调用了吗?
虽然不是直接相关,但该库的文档建议使用其他方案:
与一些替代的、维护更活跃的 WebSocket 包相比,本包目前缺少一些功能:
websocket package - github.com/gorilla/websocket - Go Packages websocket package - nhooyr.io/websocket - Go Packages
问题在于golang.org/x/net/websocket包在处理WebSocket协议时存在兼容性问题。客户端发送的WebSocket握手请求包含Sec-WebSocket-Version: 13,但该包默认使用较旧的协议版本。
以下是修复后的服务端代码:
package main
import (
"fmt"
"log"
"net/http"
"golang.org/x/net/websocket"
)
func Echo(ws *websocket.Conn) {
var err error
for {
var reply string
if err = websocket.Message.Receive(ws, &reply); err != nil {
fmt.Println("Can't receive:", err)
break
}
fmt.Println("Received back from client: " + reply)
msg := "Received: " + reply
fmt.Println("Sending to client: " + msg)
if err = websocket.Message.Send(ws, msg); err != nil {
fmt.Println("Can't send:", err)
break
}
}
}
func main() {
// 设置WebSocket处理器,指定协议版本
http.Handle("/", websocket.Handler(Echo))
// 或者使用更明确的配置
http.Handle("/ws", websocket.Handler(Echo))
fmt.Println("Server starting on :1234...")
if err := http.ListenAndServe(":1234", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
或者使用更现代的gorilla/websocket包,它支持最新的WebSocket协议:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true // 在生产环境中应进行适当的来源检查
},
}
func Echo(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 {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
fmt.Printf("Received: %s\n", message)
response := []byte(fmt.Sprintf("Received: %s", message))
if err := conn.WriteMessage(messageType, response); err != nil {
log.Println("Write error:", err)
break
}
}
}
func main() {
http.HandleFunc("/", Echo)
fmt.Println("Server starting on :1234...")
if err := http.ListenAndServe(":1234", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
客户端HTML代码也需要相应调整:
<html>
<head></head>
<body>
<script type="text/javascript">
var sock = null;
var wsuri = "ws://localhost:1234/";
window.onload = function() {
console.log("onload");
sock = new WebSocket(wsuri);
sock.onopen = function() {
console.log("connected to " + wsuri);
}
sock.onclose = function(e) {
console.log("connection closed (" + e.code + ")");
}
sock.onmessage = function(e) {
console.log("message received: " + e.data);
}
sock.onerror = function(e) {
console.log("WebSocket error: ", e);
}
};
function send() {
var msg = document.getElementById('message').value;
if (sock.readyState === WebSocket.OPEN) {
sock.send(msg);
} else {
console.log("WebSocket is not connected");
}
};
</script>
<h1>WebSocket Echo Test</h1>
<form>
<p>
Message: <input id="message" type="text" value="Hello, world!">
</p>
</form>
<button onclick="send();">Send Message</button>
</body>
</html>
使用gorilla/websocket包时,需要先安装:
go get github.com/gorilla/websocket
主要问题:
golang.org/x/net/websocket包使用旧的WebSocket协议草案- 现代浏览器默认使用RFC 6455协议版本
- 协议版本不匹配导致握手失败
修复方案:
- 使用
gorilla/websocket包(推荐) - 或者确保客户端和服务端使用兼容的协议版本
- 检查WebSocket端点路径是否正确

