gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
76.96k stars 7.92k forks source link

http: response.Write on hijacked connection from github.com/gin-gonic/gin.(*responseWriter).Write (response_writer.go:83) #3921

Open jimmylauu opened 3 months ago

jimmylauu commented 3 months ago

Description

I used gorilla/websocket combined with the gin framework, and an error occurred when connecting to websocket, indicating that the connection was hijacked.

How to reproduce

router.GET("/wss/push", pushMessage)
router.Run(":8080")
func pushMessage(c *gin.Context) {
    ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
    if err != nil {
        c.JSON(http.StatusInternalServerError, BaseResponse{Code: CODE_INTERNAL_ERROR, Message: ""})
        log.Fatalf("upgrade http to websocket fail:%s", err)
        return
    }
    defer func(ws *websocket.Conn) {
        err := ws.Close()
        if err != nil {
            c.JSON(http.StatusInternalServerError, BaseResponse{Code: CODE_INTERNAL_ERROR, Message: ""})
            log.Fatalf("close websocket fail:%s", err)
        }
    }(ws)
    go func() {
        for {
            select {
            case msg, ok := <-receiveMsg:
                if ok {
                    jsonData, err := json.Marshal(msg)
                    if err != nil {
                        c.JSON(http.StatusInternalServerError, BaseResponse{Code: CODE_INTERNAL_ERROR, Message: ""})
                        log.Printf("recevie message convert to json fail:%s", err)
                    }
                    err = ws.WriteMessage(websocket.TextMessage, jsonData)
                    if err != nil {
                        c.JSON(http.StatusInternalServerError, BaseResponse{Code: CODE_INTERNAL_ERROR, Message: ""})
                        log.Printf("websocket write message fail:%s", err)
                    }
                }
            }
        }
    }()
    c.JSON(http.StatusOK, BaseResponse{Code: CODE_SUCCESS, Message: "success"})
}

Expectations

Connect to websocket normally

Actual result

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 200 with 500
2024/04/11 19:07:59 http: response.Write on hijacked connection from github.com/gin-gonic/gin.(*responseWriter).Write (response_writer.go:83)
[GIN] 2024/04/11 - 19:07:59 | 200 |     17.8844ms |       127.0.0.1 | GET      "/wss/push"
Error #01: http: connection has been hijacked
Error #02: http: connection has been hijacked

Environment

RedCrazyGhost commented 3 months ago

The code you provided cannot be reproduced, please provide the code again