使用相同的处理程序去处理 websockets 和 HTTP

Posted

技术标签:

【中文标题】使用相同的处理程序去处理 websockets 和 HTTP【英文标题】:Go handling websockets and HTTP with the same handler 【发布时间】:2014-12-10 19:30:17 【问题描述】:

已经搜索了一段时间,但找不到直接回答这个问题的任何东西。

Go 能否使用同一个处理程序来处理 WS 连接和 HTTP 连接?

简而言之,我想复制 SignalR 之类的东西

【问题讨论】:

您希望如何在服务器上从 websocket“降级”到 http?客户端正在请求 websocket,或者不是。 抱歉,我发帖后才发现,没有及时编辑。我知道用于确定浏览器功能的客户端工具。我已将我的问题编辑为特定于服务器端。 gorillatoolkit.org/pkg/websocket 似乎暗示答案是“是”。 Upgrader.Upgrade() 将返回 nil 错误,如果它可以将协议升级到 websockets,所以你可以检查这种情况。 我也发现了这个 -talks.golang.org/2012/chat.slide#30 - 我只是不想有重复的 WS 和 HTTP 处理程序 【参考方案1】:

是的,gorilla/websocket 包支持在请求处理程序中从 HTTP 升级到 WebSocket。请参阅beginning of the package documentation 中的示例。函数handler 是一个标准的HTTP 请求处理程序。对upgrader.Upgrade 的调用将连接切换到WebSocket 协议。

x/net/websocket 包需要单独的处理程序。有other reasons为什么你可能不想使用 x/net/websocket 包。

【讨论】:

【参考方案2】:

在将请求传递给upgrader.upgrade 方法之前,我最终需要自己过滤请求。因为upgrader.upgrade,在升级请求失败时,写'Bad request' 响应给它。将我的 html 呈现为纯文本,并在开头附加“错误请求”文本。

这就是我在handler顶部所做的:

func singleHandler(w http.ResponseWriter, r *http.Request) 
    upgrade := false
    for _, header := range r.Header["Upgrade"] 
        if header == "websocket" 
            upgrade = true
            break
        
    

    if upgrade == false 
        if r.Method != "GET" 
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
            return
        
        if r.URL.Path != "/" 
            http.NotFound(w, r)
            return
        
        chatTemplate.Execute(w, listenAddr)
        return
    

    c, err := upgrader.Upgrade(w, r, nil)
    if err != nil 
        log.Print("Upgrade err:", err)
        return
    

    ...

这是一个示例 repo:https://github.com/siriusdely/gochat。基于 Andrew Gerrand 的演讲:优雅成长的代码 https://talks.golang.org/2012/chat.slide#44。

【讨论】:

以上是关于使用相同的处理程序去处理 websockets 和 HTTP的主要内容,如果未能解决你的问题,请参考以下文章

瓶子 + WebSocket

在调用处理程序之前使用 Tomcat 8 和 Spring 4 ClassCastException 的 websockets

使用 React、Redux 和 Websocket 处理请求

Websockets 在客户端发送多个事件和多个事件处理程序

Vue中使用websocket的正确使用方法

在牛仔 websocket 处理程序中使用 gproc 注册两个本地进程时出现问题