You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang实现WebSocket Echo服务时连接快速关闭问题

问题描述

测试如下WebSocket示例时,出现连接建立后快速关闭的错误。

原有服务端代码(Golang)

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.org/x/net/websocket包长期未更新,完全不兼容现代浏览器遵循的WebSocket RFC 6455标准:

  • 该包握手阶段的Origin校验逻辑不符合规范,会直接拒绝浏览器发起的合法握手请求,返回403状态码触发连接断开
  • 帧解析逻辑存在兼容缺陷,无法正确识别Chrome、Firefox等主流新版浏览器发送的WebSocket数据帧
修复方案

替换为Go生态广泛使用、完全符合标准的gorilla/websocket库实现服务端,操作步骤如下:

  • 安装依赖库,执行命令:
    go get github.com/gorilla/websocket
    
  • 替换原有服务端代码为以下版本:
    package main
    
    import (
        "fmt"
        "log"
        "net/http"
    
        "github.com/gorilla/websocket"
    )
    
    var upgrader = websocket.Upgrader{
        // 测试阶段允许所有跨域请求,生产环境请根据实际业务校验请求来源
        CheckOrigin: func(r *http.Request) bool {
            return true
        },
    }
    
    func Echo(w http.ResponseWriter, r *http.Request) {
        ws, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Println("WebSocket连接升级失败:", err)
            return
        }
        defer ws.Close()
    
        for {
            _, reply, err := ws.ReadMessage()
            if err != nil {
                fmt.Println("接收消息失败,连接已断开")
                break
            }
            replyStr := string(reply)
            fmt.Println("收到客户端消息: " + replyStr)
    
            msg := "Received:  " + replyStr
            fmt.Println("向客户端发送消息: " + msg)
    
            err = ws.WriteMessage(websocket.TextMessage, []byte(msg))
            if err != nil {
                fmt.Println("发送消息失败")
                break
            }
        }
    }
    
    func main() {
        http.HandleFunc("/", Echo)
        if err := http.ListenAndServe(":1234", nil); err != nil {
            log.Fatal("ListenAndServe:", err)
        }
    }
    

原有前端代码不需要做任何修改,重新启动服务端后即可正常建立连接、收发消息。


内容的提问来源于stack exchange,提问作者Hasan A Yousef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 17:27:23