showliuzp 2025-10-16 17:49 采纳率: 84.3%
浏览 3
已结题

golang gorilla/websocket模拟post请求报错

//我部署了一个gorilla的一个websocket

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

    r = []rest.Route{

       add_router(types.GET,"/ws/",WsChat),    //

    }

    return r
}

type HandlerFunc func(w http.ResponseWriter, r *http.Request)

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,
    }
}
type HandlerFunc func(w http.ResponseWriter, r *http.Request)

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,
    }
}

//允许websocket
func WsChat(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Printf("错误内容:%+v\n",err)
        return
    }

    defer conn.Close()
    // 设置关闭处理函数
    conn.SetCloseHandler(func(code int, text string) error {
        //处理下线逻辑
        fmt.Printf("Connection closed [%s]\n", conn.RemoteAddr().String())
        return nil
    })

    //fmt.Printf("Connection open [%s]:\n", conn.RemoteAddr().String())
    for {
        messageType, message, err := conn.ReadMessage()
        if err != nil{
            if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
                    fmt.Printf("连接关闭[%+v]\n", err)
            }else{
                fmt.Printf("连接异常关闭[%+v]\n", err)
            }
            break
        }

        if messageType == websocket.TextMessage {
            //接收消息
            fmt.Printf("Received [%s]:\nmessage:%s", conn.RemoteAddr().String(), message)
            //发送消息
            sendMsg := "服务器返回:" + string(message) + "[收到]"
            err = conn.WriteMessage(messageType, []byte(sendMsg))
            fmt.Printf("Send [%s]:\nmessage:%s", conn.RemoteAddr().String(), sendMsg)
            if err != nil {
                fmt.Println(err)
                break
            }
        }
    }
}


gorilla的源码中对请求的校验,server.go
136     if r.Method != http.MethodGet {
137         return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
138     }


也就是如果是post请求,将会报405,并返回包含request method is not GET的消息
但我用postman请求,返回的是404,并且没有错误消息

![img](https://i-blog.csdnimg.cn/ask/a1a833ac866a4066979af1d628ef031c.png "#left")

![img](https://i-blog.csdnimg.cn/ask/d2ab2ba358a6428ebfbe7da79852e26c.png "#left")

我怎样才能让gorilla抛出405,和request method is not GET
  • 写回答

5条回答 默认 最新

  • 檀越@新空间 2025-10-16 17:50
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    根据你的描述,你正在使用 Gorilla WebSocket 来创建一个 WebSocket 服务,并且在尝试通过 POST 请求访问 /ws/ 路径时遇到了问题:返回 404 而不是预期的 405(Method Not Allowed),并且没有显示错误信息。这说明你的路由配置可能存在问题。


    问题分析

    1. WebSocket 路由只允许 GET 方法
      Gorilla WebSocket 的 Upgrade 函数要求请求方法为 GET,否则会返回 405 Method Not Allowed 错误,如你提到的源码部分所示。

    2. 你的路由配置中可能没有正确绑定 /ws/ 路由
      从你提供的代码来看,Router() 函数定义了 /ws/ 路由,但你用的是 types.Admin_Http_URL_Prefix + path,如果该前缀未正确设置或与实际路径不匹配,可能导致请求被错误地处理,从而返回 404。

    3. POST 请求无法进入 WebSocket 处理逻辑
      因为 WebSocket 升级只支持 GET 请求,所以如果你发送的是 POST 请求,Gorilla WebSocket 会在升级时抛出错误。但如果这个请求没有正确进入你的 WsChat 函数,可能是路由未被正确注册。


    解决方案

    1. 确保 /ws/ 路由正确注册

    检查 types.Admin_Http_URL_Prefix 是否与你实际访问的 URL 匹配。例如:

    • 如果你访问的是 http://localhost:8080/ws/
    • 那么 types.Admin_Http_URL_Prefix 应该是 "http://localhost:8080/" 或者空字符串。
    • 如果 types.Admin_Http_URL_Prefix"api/",那么实际路径应为 http://localhost:8080/api/ws/

    重点:确保你的路由路径和实际访问路径完全一致


    2. 检查是否将 /ws/ 路由绑定到正确的 HTTP 方法

    你目前的路由定义如下:

    add_router(types.GET, "/ws/", WsChat)
    

    这意味着只有 GET 请求会被路由到 WsChat 函数。而如果你用 POST 请求访问 /ws/,它不会进入 WsChat 函数,而是可能被其他默认路由或错误处理逻辑捕获,导致返回 404。


    3. 明确区分 WebSocket 和普通 HTTP 接口

    WebSocket 的握手过程必须使用 GET 请求,因此你不能用 POST 来测试 WebSocket 连接。POST 请求无法连接 WebSocket,这是协议层面的限制。

    重点:WebSocket 的握手只能使用 GET 方法,POST 请求无法建立 WebSocket 连接


    4. 如何模拟 WebSocket 连接?

    你可以使用以下方式测试 WebSocket:

    ✅ 使用 Postman 测试 WebSocket:

    • 打开 Postman
    • 设置请求类型为 WebSocket
    • 输入地址:ws://localhost:8080/ws/
    • 发送消息,观察响应

    ✅ 使用命令行工具(如 wscat):

    npm install -g wscat
    wscat -c ws://localhost:8080/ws/
    

    5. 如果你确实需要使用 POST 请求进行某些操作(非 WebSocket)

    如果你希望使用 POST 请求来触发 WebSocket 消息或其他逻辑,可以考虑以下方式:

    • 创建一个独立的 HTTP 接口(如 /send-message),接收 POST 请求
    • 在该接口中,通过某种方式向 WebSocket 客户端发送消息(例如维护客户端列表)
    • 示例代码如下:
    func SendMessage(w http.ResponseWriter, r *http.Request) {
        if r.Method != "POST" {
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
            return
        }
    
        // 读取 POST 数据
        body, _ := io.ReadAll(r.Body)
        message := string(body)
    
        // 将消息广播给所有 WebSocket 客户端
        for _, conn := range clients {
            err := conn.WriteMessage(websocket.TextMessage, []byte("Server received: "+message))
            if err != nil {
                fmt.Println("Error sending message:", err)
            }
        }
    
        w.Write([]byte("Message sent"))
    }
    

    6. 修改你的路由以包含 POST 接口(可选)

    如果你希望同时支持 WebSocket 和 POST 接口,可以这样写:

    r = []rest.Route{
        add_router(types.GET, "/ws/", WsChat),
        add_router(types.POST, "/send-message", SendMessage),
    }
    

    总结

    | 步骤 | 内容 | |------|------| | 1 | 确保 /ws/ 路由路径正确,避免 404 | | 2 | WebSocket 握手只能使用 GET 方法,POST 无法建立连接 | | 3 | 使用 Postman 或 wscat 测试 WebSocket 连接 | | 4 | 若需 POST 接口,创建独立的 HTTP 接口并处理逻辑 |


    最终建议

    如果你的目标是 模拟 POST 请求,请不要尝试连接 WebSocket,而是使用标准的 HTTP POST 接口;
    如果你的目标是 测试 WebSocket 连接,请使用 WebSocket 客户端工具(如 Postman、wscat)。

    如需进一步帮助,请提供完整的项目结构和启动代码,我可以帮你更详细地调试。

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

报告相同问题?

问题事件

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