golang websocket当浏览器意外关闭时如何通知

I am writing a websocket service in golang. The program use gollira websocket to accept ws request, and in each request handler, it listen to rabbitmq queue for messages.

The problem is, when i close browser window, the handler thread is still running, i guess there is an mechanism to be notified when connection disconnected.

I try to listen to channel request.Context().Done(), when i doesn't work.

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

If the browser cleanly closes the connection, then read on the webssocket connection returns an error. Cleanup the websocket connection as you would on any read error.

The application must PING the connection and expect the corresponding PONGs to detect other situations. The chat example shows how to send PINGs and receive PONGs.