showliuzp 2025-10-17 21:06 采纳率: 84.3%
浏览 4
已结题

golang websocket返回http错误码

//websocket路由
func add_router(method_type string, path string, handler http.HandlerFunc) rest.Route {
    return rest.Route{
        Method:  method_type,
        Path:    types.Admin_Http_URL_Prefix + path,
        Handler: handler,
    }
}

func Router() (r []rest.Route) {
    login_chk := services.NewLogin()

    r = []rest.Route{
add_router(types.GET,"/ws/",WsChat),
  }

controller.go
func WsChat(w http.ResponseWriter, r *http.Request) {
    var (
        conn *websocket.Conn
        err error
        )

    //先进行登录身份校验,获取当前用户id,昵称基础信息
    authorization := (*r).Header.Get("authorization")
    if len(authorization) < 1{
        fmt.Printf("错误\n")
        http.Error(w, "token校验失败", http.StatusInternalServerError)
        return
    }
}

//我在建立一个websocket的连接,在建立之前需要对header头的authorization进行,如果不合法则返回错误消息,但在浏览器访问前端页面,没有任何输出,怎么能输出错误呢?
前端页面:
<!DOCTYPE html>
<html>
<head>
 <title>go websocket</title>
 <meta charset="utf-8" />  
</head>
<body>
 <script type="text/javascript">
  var wsUri ="ws://192.168.5.17:33121/api/dd/ws"; 
     var output;  
     
     function init() { 
         output = document.getElementById("output"); 
         testWebSocket(); 
     }  
  
     function testWebSocket() { 
         websocket = new WebSocket(wsUri); 
         websocket.onopen = function(evt) { 
             onOpen(evt) 
         }; 
         websocket.onclose = function(evt) { 
             onClose(evt) 
         }; 
         websocket.onmessage = function(evt) { 
             onMessage(evt) 
         }; 
         websocket.onerror = function(evt) { 
             onError(evt) 
         }; 
     }  
  
     function onOpen(evt) { 
         writeToScreen("CONNECTED"); 
        // doSend("WebSocket rocks"); 
     }  
  
     function onClose(evt) { 
         writeToScreen("DISCONNECTED"); 
     }  
  
     function onMessage(evt) { 
         writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>'); 
        // websocket.close(); 
     }  
  
     function onError(evt) { 
         writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data); 
     }  
  
     function doSend(message) { 
         writeToScreen("SENT: " + message);  
         websocket.send(message); 
     }  
  
     function writeToScreen(message) { 
         var pre = document.createElement("p"); 
         pre.style.wordWrap = "break-word"; 
         pre.innerHTML = message; 
         output.appendChild(pre); 
     }  
  
     window.addEventListener("load", init, false);  
     function sendBtnClick(){
      var msg = document.getElementById("input").value;
      doSend(msg);
      document.getElementById("input").value = '';
     }
     function closeBtnClick(){
      websocket.close(); 
     }
</script>
 <h2>WebSocket Test</h2>  
 <input type="text" id="input"></input>
 <button onclick="sendBtnClick()" >send</button>
 <button onclick="closeBtnClick()" >close</button>
 <div id="output"></div>  
 
</body>
</html>

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-10-17 21:09
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:努力的意义,在于当机会来临时,你有能力抓住它。
    .

    Golang WebSocket 返回 HTTP 错误码的解决方案

    在您的代码中,当 WebSocket 连接的身份校验失败时,您使用了 http.Error 返回错误,但这在 WebSocket 连接中无法被前端正确捕获。以下是解决方案:

    问题分析

    当 WebSocket 握手阶段返回 HTTP 错误码时,浏览器会触发 onerror 事件,但 evt.data 通常为空。您需要修改后端代码以正确返回 WebSocket 握手错误。

    后端修改

    func WsChat(w http.ResponseWriter, r *http.Request) {
        // 先进行登录身份校验
        authorization := r.Header.Get("Authorization")
        if len(authorization) < 1 {
            // WebSocket 握手失败时返回 401 状态码
            w.WriteHeader(http.StatusUnauthorized)
            w.Write([]byte("token校验失败"))
            return
        }
        
        // 身份验证通过,升级为 WebSocket 连接
        upgrader := websocket.Upgrader{
            CheckOrigin: func(r *http.Request) bool {
                return true // 在生产环境中应该检查来源
            },
        }
        
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Printf("WebSocket upgrade failed: %v", err)
            return
        }
        defer conn.Close()
        
        // 处理 WebSocket 连接
        for {
            messageType, message, err := conn.ReadMessage()
            if err != nil {
                log.Printf("Read error: %v", err)
                break
            }
            
            // 处理消息
            err = conn.WriteMessage(messageType, message)
            if err != nil {
                log.Printf("Write error: %v", err)
                break
            }
        }
    }
    

    前端修改

    function onError(evt) {
        writeToScreen('<span style="color: red;">ERROR:</span> WebSocket连接失败');
        // 可以在这里添加更详细的错误处理
        console.error('WebSocket error:', evt);
    }
    
    
    function testWebSocket() {
        websocket = new WebSocket(wsUri);
        
        // 添加认证头信息
        websocket.onopen = function(evt) {
            onOpen(evt);
        };
        
        websocket.onclose = function(evt) {
            // 根据关闭代码判断是否为认证失败
            if (evt.code === 1008 || evt.code === 4000) {
                writeToScreen('<span style="color: red;">认证失败:</span> ' + evt.reason);
            } else {
                writeToScreen("DISCONNECTED");
            }
        };
        
        websocket.onmessage = function(evt) {
            onMessage(evt);
        };
        
        websocket.onerror = function(evt) {
            onError(evt);
        };
    }
    

    完整的改进方案

    后端完整代码

    import (
        "net/http"
        "github.com/gorilla/websocket"
    )
    
    
    var upgrader = websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool {
            return true // 生产环境应根据需要配置
        },
    }
    
    
    func WsChat(w http.ResponseWriter, r *http.Request) {
        // 身份验证
        if !authenticate(r) {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Printf("WebSocket upgrade failed: %v", err)
            return
        }
        defer conn.Close()
        
        // WebSocket 通信逻辑
        handleWebSocketConnection(conn)
    }
    
    
    func authenticate(r *http.Request) bool {
        authorization := r.Header.Get("Authorization")
        return len(authorization) > 0 // 这里应该实现实际的认证逻辑
    }
    
    
    func handleWebSocketConnection(conn *websocket.Conn) {
        for {
            messageType, message, err := conn.ReadMessage()
            if err != nil {
                if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
                    log.Printf("WebSocket error: %v", err)
                }
                break
            }
            
            // 处理接收到的消息
            processMessage(conn, messageType, message)
        }
    }
    
    
    func processMessage(conn *websocket.Conn, messageType int, message []byte) {
        // 这里实现您的业务逻辑
        err := conn.WriteMessage(messageType, message)
        if err != nil {
            log.Printf("Write error: %v", err)
        }
    }
    

    前端完整代码

    <!DOCTYPE html>
    <html>
    <head>
        <title>go websocket</title>
        <meta charset="utf-8" />  
    </head>
    <body>
        <script type="text/javascript">
            var wsUri = "ws://192.168.5.17:33121/api/dd/ws"; 
            var output;  
            var websocket;
            
            function init() { 
                output = document.getElementById("output"); 
                testWebSocket(); 
            }  
        
            function testWebSocket() { 
                websocket = new WebSocket(wsUri); 
                
                websocket.onopen = function(evt) { 
                    onOpen(evt); 
                }; 
                
                websocket.onclose = function(evt) { 
                    onClose(evt); 
                }; 
                
                websocket.onmessage = function(evt) { 
                    onMessage(evt); 
                }; 
                
                websocket.onerror = function(evt) { 
                    onError(evt); 
                }; 
            }  
        
            function onOpen(evt) { 
                writeToScreen("CONNECTED"); 
            }  
        
            function onClose(evt) { 
                if (evt.code !== 1000) { // 正常关闭代码是1000
                    writeToScreen('<span style="color: red;">连接异常关闭: 代码=' + evt.code + ', 原因=' + (evt.reason || '未知') + '</span>');
                } else {
                    writeToScreen("DISCONNECTED"); 
                }
            }  
        
            function onMessage(evt) { 
                writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>'); 
            }  
        
            function onError(evt) { 
                writeToScreen('<span style="color: red;">连接错误</span>'); 
            }  
        
            function doSend(message) { 
                if (websocket.readyState === WebSocket.OPEN) {
                    writeToScreen("SENT: " + message);  
                    websocket.send(message); 
                } else {
                    writeToScreen('<span style="color: orange;">消息发送失败: 连接未就绪</span>');
                }
            }  
        
            function writeToScreen(message) { 
                var pre = document.createElement("p"); 
                pre.style.wordWrap = "break-word"; 
                pre.innerHTML = message; 
                output.appendChild(pre); 
            }  
        
            window.addEventListener("load", init, false);  
            
            function sendBtnClick(){
                var msg = document.getElementById("input").value;
                if (msg.trim() !== '') {
                    doSend(msg);
                    document.getElementById("input").value = '';
                }
            }
            
            function closeBtnClick(){
                if (websocket) {
                    websocket.close(1000, "用户主动关闭"); 
                }
            }
        </script>
        
        <h2>WebSocket Test</h2>  
        <input type="text" id="input" placeholder="输入消息..."></input>
        <button onclick="sendBtnClick()">发送</button>
        <button onclick="closeBtnClick()">关闭连接</button>
        <div id="output"></div>  
    </body>
    </html>
    

    关键改进点

    1. 后端身份验证失败时:直接返回 HTTP 状态码,而不是尝试升级为 WebSocket
    2. 前端错误处理:在 onclose 事件中检查关闭代码,判断是否为认证失败
    3. 连接状态检查:在发送消息前检查 WebSocket 连接状态
    4. 更详细的错误信息:提供更清晰的错误提示

    这样修改后,当身份验证失败时,前端能够正确显示错误信息。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 10月25日
  • 已采纳回答 10月17日
  • 创建了问题 10月17日