Ich benutze Go schon seit einiger Zeit, habe SSE aber noch nie zuvor verwendet. Ich habe ein Problem. Kann jemand ein funktionierendes Beispiel für ein vom Server gesendetes Ereignis bereitstellen, das nur an einen bestimmten Benutzer (Verbindung) gesendet wird?
Ich verwende die Gorilla-Sitzung zur Authentifizierung und möchte die Benutzer-ID verwenden, um die Verbindungen zu trennen.
Oder sollte ich eine 5-Sekunden-Abfrage über Ajax verwenden?
Vielen Dank
Das habe ich gefunden und ausprobiert:
https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c Es wird nicht an einzelne Benutzer gesendet und die Go-Funktion wird nicht beendet, wenn die Verbindung geschlossen wird
https://github.com/striversity/gotr/blob/master/010-server-sent-event-part-2/main.go Das ist genau das, was ich brauche, aber sobald die Verbindung gelöscht wird. Wenn Sie nun den Browser schließen und in einem privaten Fenster öffnen, funktioniert es überhaupt nicht mehr. Außerdem wird, wie oben erwähnt, die Go-Routine fortgesetzt.
Erstellen Sie einen „Broker“, um Nachrichten an verbundene Benutzer zu verteilen:
type broker struct { // users is a map where the key is the user id // and the value is a slice of channels to connections // for that user id users map[string][]chan []byte // actions is a channel of functions to call // in the broker's goroutine. the broker executes // everything in that single goroutine to avoid // data races. actions chan func() } // run executes in a goroutine. it simply gets and // calls functions. func (b *broker) run() { for a := range b.actions { a() } } func newbroker() *broker { b := &broker{ users: make(map[string][]chan []byte), actions: make(chan func()), } go b.run() return b } // adduserchan adds a channel for user with given id. func (b *broker) adduserchan(id string, ch chan []byte) { b.actions <- func() { b.users[id] = append(b.users[id], ch) } } // removeuserchan removes a channel for a user with the given id. func (b *broker) removeuserchan(id string, ch chan []byte) { // the broker may be trying to send to // ch, but nothing is receiving. pump ch // to prevent broker from getting stuck. go func() { for range ch {} }() b.actions <- func() { chs := b.users[id] i := 0 for _, c := range chs { if c != ch { chs[i] = c i = i + 1 } } if i == 0 { delete(b.users, id) } else { b.users[id] = chs[:i] } // close channel to break loop at beginning // of removeuserchan. // this must be done in broker goroutine // to ensure that broker does not send to // closed goroutine. close(ch) } } // sendtouser sends a message to all channels for the given user id. func (b *broker) sendtouser(id string, data []byte) { b.actions <- func() { for _, ch := range b.users[id] { ch <- data } } }
Variablen auf Paketebene mithilfe von Proxys deklarieren:
var broker = newbroker()
SSE-Endpunkt mit Proxy schreiben:
func sseEndpoint(w http.ResponseWriter, r *http.Request) { // I assume that user id is in query string for this example, // You should use your authentication code to get the id. id := r.FormValue("id") // Do the usual SSE setup. flusher := w.(http.Flusher) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") // Create channel to receive messages for this connection. // Register that channel with the broker. // On return from the function, remove the channel // from the broker. ch := make(chan []byte) broker.addUserChan(id, ch) defer broker.removeUserChan(id, ch) for { select { case <-r.Context().Done(): // User closed the connection. We are out of here. return case m := <-ch: // We got a message. Do the usual SSE stuff. fmt.Fprintf(w, "data: %s\n\n", m) flusher.Flush() } } }
Fügen Sie Code zu Ihrer Anwendung hinzu, um Broker.sendtouser aufzurufen.
Das obige ist der detaillierte Inhalt vonVom Golang-Server an jeden Benutzer gesendete Ereignisse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!