溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

構(gòu)建一個(gè)即時(shí)消息應(yīng)用之什么是實(shí)時(shí)消息

發(fā)布時(shí)間:2021-10-26 16:25:36 來源:億速云 閱讀:135 作者:iii 欄目:編程語言

這篇文章主要講解了“構(gòu)建一個(gè)即時(shí)消息應(yīng)用之什么是實(shí)時(shí)消息”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“構(gòu)建一個(gè)即時(shí)消息應(yīng)用之什么是實(shí)時(shí)消息”吧!

消息戶端

在 HTTP 部分之前,讓我們先編寫一個(gè)映射map ,讓所有客戶端都監(jiān)聽消息。 像這樣全局初始化:

type MessageClient struct {     Messages chan Message     UserID   string }  var messageClients sync.Map

已創(chuàng)建的新消息

還記得在 上一篇文章 中,當(dāng)我們創(chuàng)建這條消息時(shí),我們留下了一個(gè) “TODO” 注釋。在那里,我們將使用這個(gè)函數(shù)來調(diào)度一個(gè) goroutine。

go messageCreated(message)

把這行代碼插入到我們留注釋的位置。

func messageCreated(message Message) error {     if err := db.QueryRow(`         SELECT user_id FROM participants         WHERE user_id != $1 and conversation_id = $2     `, message.UserID, message.ConversationID).     Scan(&message.ReceiverID); err != nil {         return err     }      go broadcastMessage(message)      return nil }  func broadcastMessage(message Message) {     messageClients.Range(func(key, _ interface{}) bool {         client := key.(*MessageClient)         if client.UserID == message.ReceiverID {             client.Messages <- message         }         return true     }) }

該函數(shù)查詢接收者 ID(其他參與者 ID),并將消息發(fā)送給所有客戶端。

訂閱消息

讓我們轉(zhuǎn)到 main() 函數(shù)并添加以下路由:

router.HandleFunc("GET", "/api/messages", guard(subscribeToMessages))

此端點(diǎn)處理 /api/messages 上的 GET 請(qǐng)求。請(qǐng)求應(yīng)該是一個(gè) EventSource 連接。它用一個(gè)事件流響應(yīng),其中的數(shù)據(jù)是 JSON 格式的。

func subscribeToMessages(w http.ResponseWriter, r *http.Request) {     if a := r.Header.Get("Accept"); !strings.Contains(a, "text/event-stream") {         http.Error(w, "This endpoint requires an EventSource connection", http.StatusNotAcceptable)         return     }      f, ok := w.(http.Flusher)     if !ok {         respondError(w, errors.New("streaming unsupported"))         return     }      ctx := r.Context()     authUserID := ctx.Value(keyAuthUserID).(string)      h := w.Header()     h.Set("Cache-Control", "no-cache")     h.Set("Connection", "keep-alive")     h.Set("Content-Type", "text/event-stream")      messages := make(chan Message)     defer close(messages)      client := &MessageClient{Messages: messages, UserID: authUserID}     messageClients.Store(client, nil)     defer messageClients.Delete(client)      for {         select {         case <-ctx.Done():             return         case message := <-messages:             if b, err := json.Marshal(message); err != nil {                 log.Printf("could not marshall message: %v\n", err)                 fmt.Fprintf(w, "event: error\ndata: %v\n\n", err)             } else {                 fmt.Fprintf(w, "data: %s\n\n", b)             }             f.Flush()         }     } }

首先,它檢查請(qǐng)求頭是否正確,并檢查服務(wù)器是否支持流式傳輸。我們創(chuàng)建一個(gè)消息通道,用它來構(gòu)建一個(gè)客戶端,并將其存儲(chǔ)在客戶端映射中。每當(dāng)創(chuàng)建新消息時(shí),它都會(huì)進(jìn)入這個(gè)通道,因此我們可以通過 for-select 循環(huán)從中讀取。

服務(wù)器發(fā)送事件Server-Sent Events使用以下格式發(fā)送數(shù)據(jù):

data: some data here\n\n

我們以 JSON 格式發(fā)送:

data: {"foo":"bar"}\n\n

我們使用 fmt.Fprintf() 以這種格式寫入響應(yīng)寫入器writter,并在循環(huán)的每次迭代中刷新數(shù)據(jù)。

這個(gè)循環(huán)會(huì)一直運(yùn)行,直到使用請(qǐng)求上下文關(guān)閉連接為止。我們延遲了通道的關(guān)閉和客戶端的刪除,因此,當(dāng)循環(huán)結(jié)束時(shí),通道將被關(guān)閉,客戶端不會(huì)收到更多的消息。

注意,服務(wù)器發(fā)送事件Server-Sent Events(EventSource)的 JavaScript API 不支持設(shè)置自定義請(qǐng)求頭?,所以我們不能設(shè)置 Authorization: Bearer <token>。這就是為什么 guard() 中間件也會(huì)從 URL 查詢字符串中讀取令牌的原因。

感謝各位的閱讀,以上就是“構(gòu)建一個(gè)即時(shí)消息應(yīng)用之什么是實(shí)時(shí)消息”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)構(gòu)建一個(gè)即時(shí)消息應(yīng)用之什么是實(shí)時(shí)消息這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI