golang websocket如何在浏览器意外关闭时收到通知

时间:2017-06-08 04:24:15

标签: go websocket gorilla

我正在golang中编写websocket服务。 该程序使用gollira websocket接受ws请求,并在每个请求处理程序中,它监听rabbitmq队列中的消息。

问题是,当我关闭浏览器窗口时,处理程序线程仍然在运行,我想有一种机制可以在连接断开时得到通知。

我尝试收听频道request.Context()。Done(),当我不工作时。

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/websocket"
    "github.com/streadway/amqp"
)

var (
    addr     = "localhost:9999"
    upgrader = websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool { return true },
    }
)

var conn *amqp.Connection

func watch(w http.ResponseWriter, r *http.Request) {
    ns := r.URL.Query().Get("ns")
    if ns == "" {
        return
    }
    c, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Print("upgrade:", err)
        return
    }
    defer c.Close()

    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    err = ch.ExchangeDeclare(
        "notify", // name
        "fanout",           // type
        true,               // durable
        false,              // auto-deleted
        false,              // internal
        false,              // no-wait
        nil,                // arguments
    )
    failOnError(err, "Failed to declare an exchange")

    q, err := ch.QueueDeclare(
        "",    // name
        false, // durable
        false, // delete when usused
        true,  // exclusive
        false, // no-wait
        nil,   // arguments
    )
    failOnError(err, "Failed to declare a queue")

    err = ch.QueueBind(
        q.Name,             // queue name
        ns,                 // routing key
        "dsm_tasks_notify", // exchange
        false,
        nil)
    failOnError(err, "Failed to bind a queue")

    msgs, err := ch.Consume(
        q.Name, // queue
        "",     // consumer
        true,   // auto-ack
        false,  // exclusive
        false,  // no-local
        false,  // no-wait
        nil,    // args
    )
    failOnError(err, "Failed to register a consumer")

    for {
        select {
        case d := <-msgs:
            err = c.WriteMessage(websocket.TextMessage, d.Body)
            if err != nil {
                log.Println("write:", err)
                break
            }
        case <-r.Context().Done():
            log.Println("Disconnect")
            return
        }
    }

}

func failOnError(err error, msg string) {
    if err != nil {
        log.Fatalf("%s: %s", msg, err)
        panic(fmt.Sprintf("%s: %s", msg, err))
    }
}

func main() {
    var err error
    conn, err = amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    http.HandleFunc("/watch", watch)
    log.Fatal(http.ListenAndServe(addr, nil))
}

1 个答案:

答案 0 :(得分:1)

如果浏览器干净地关闭连接,则读取webssocket连接会返回错误。像对任何读取错误一样清理websocket连接。

应用程序必须PING连接并期望相应的PONG检测其他情况。 chat example显示了如何发送PING并接收PONG。