golang websocket如何在浏览器意外关闭时得到通知
golang websocket how to be notified when browser closed unexpectly
我正在用 golang 编写一个 websocket 服务。
该程序使用 gollira websocket 来接受 ws 请求,并在每个请求处理程序中监听 rabbitmq 队列中的消息。
问题是,当我关闭浏览器时window,处理程序线程仍然运行,我想有一种机制可以在连接断开时得到通知。
当我不工作时,我尝试收听频道 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))
}
如果浏览器干净利落地关闭连接,则在webssocket连接上读取returns一个错误。像处理任何读取错误一样清理 websocket 连接。
应用程序必须 PING 连接并期望相应的 PONG 检测其他情况。 chat example 展示了如何发送 PING 和接收 PONG。
我正在用 golang 编写一个 websocket 服务。 该程序使用 gollira websocket 来接受 ws 请求,并在每个请求处理程序中监听 rabbitmq 队列中的消息。
问题是,当我关闭浏览器时window,处理程序线程仍然运行,我想有一种机制可以在连接断开时得到通知。
当我不工作时,我尝试收听频道 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))
}
如果浏览器干净利落地关闭连接,则在webssocket连接上读取returns一个错误。像处理任何读取错误一样清理 websocket 连接。
应用程序必须 PING 连接并期望相应的 PONG 检测其他情况。 chat example 展示了如何发送 PING 和接收 PONG。