我使用 Go 已經有一段時間了,但之前從未使用過 SSE。我遇到了一個問題,有人可以提供一個僅發送給特定用戶(連接)的伺服器發送事件的工作範例嗎?
我正在使用 gorilla - 會話進行身份驗證,並且我想使用 UserID 來分隔連接。
或者我應該透過 Ajax 使用 5 秒輪詢?
非常感謝
這是我發現並嘗試過的:
https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c 它不會發送給個人用戶,如果連接關閉,go func 也不會停止
https://github.com/striversity/gotr/blob/master/010-server-sent-event-part-2/main.go 這正是我所需要的,但一旦連線被刪除。所以現在,一旦您在私人視窗中關閉並打開瀏覽器,它就根本無法工作。另外,如上所述,Go 例程繼續進行。
建立一個「代理」來將訊息分發給連接的使用者:
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 } } }
在套件層級使用代理宣告變數:
var broker = newbroker()
使用代理程式編寫 sse 端點:
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() } } }
向您的應用程式添加程式碼以呼叫 broker.sendtouser。
以上是Golang 伺服器傳送給每個使用者的事件的詳細內容。更多資訊請關注PHP中文網其他相關文章!