成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

構(gòu)建一個即時消息應(yīng)用(五):實時消息

開發(fā) 后端
對于實時消息,我們將使用 服務(wù)器發(fā)送事件。這是一個打開的連接,我們可以在其中傳輸數(shù)據(jù)流。我們會有個端點,用戶會在其中訂閱發(fā)送給他的所有消息。

[[345206]]

本文是該系列的第五篇。

對于實時消息,我們將使用 服務(wù)器發(fā)送事件Server-Sent Events。這是一個打開的連接,我們可以在其中傳輸數(shù)據(jù)流。我們會有個端點,用戶會在其中訂閱發(fā)送給他的所有消息。

消息戶端

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

  1. type MessageClient struct { 
  2.     Messages chan Message 
  3.     UserID   string 
  4.  
  5. var messageClients sync.Map 

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

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

  1. go messageCreated(message) 

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

  1. func messageCreated(message Message) error { 
  2.     if err := db.QueryRow(` 
  3.         SELECT user_id FROM participants 
  4.         WHERE user_id != $1 and conversation_id = $2 
  5.     `, message.UserID, message.ConversationID). 
  6.     Scan(&message.ReceiverID); err != nil { 
  7.         return err 
  8.     } 
  9.  
  10.     go broadcastMessage(message) 
  11.  
  12.     return nil 
  13.  
  14. func broadcastMessage(message Message) { 
  15.     messageClients.Range(func(key, _ interface{}) bool { 
  16.         client := key.(*MessageClient) 
  17.         if client.UserID == message.ReceiverID { 
  18.             client.Messages <- message 
  19.         } 
  20.         return true 
  21.     }) 

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

訂閱消息

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

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

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

  1. func subscribeToMessages(w http.ResponseWriter, r *http.Request) { 
  2.     if a := r.Header.Get("Accept"); !strings.Contains(a, "text/event-stream") { 
  3.         http.Error(w, "This endpoint requires an EventSource connection", http.StatusNotAcceptable) 
  4.         return 
  5.     } 
  6.  
  7.     f, ok := w.(http.Flusher) 
  8.     if !ok { 
  9.         respondError(w, errors.New("streaming unsupported")) 
  10.         return 
  11.     } 
  12.  
  13.     ctx := r.Context() 
  14.     authUserID := ctx.Value(keyAuthUserID).(string) 
  15.  
  16.     h := w.Header() 
  17.     h.Set("Cache-Control""no-cache"
  18.     h.Set("Connection""keep-alive"
  19.     h.Set("Content-Type""text/event-stream"
  20.  
  21.     messages := make(chan Message) 
  22.     defer close(messages) 
  23.  
  24.     client := &MessageClient{Messages: messages, UserID: authUserID} 
  25.     messageClients.Store(client, nil) 
  26.     defer messageClients.Delete(client) 
  27.  
  28.     for { 
  29.         select { 
  30.         case <-ctx.Done(): 
  31.             return 
  32.         case message := <-messages: 
  33.             if b, err := json.Marshal(message); err != nil { 
  34.                 log.Printf("could not marshall message: %v\n", err) 
  35.                 fmt.Fprintf(w, "event: error\ndata: %v\n\n", err) 
  36.             } else { 
  37.                 fmt.Fprintf(w, "data: %s\n\n", b) 
  38.             } 
  39.             f.Flush() 
  40.         } 
  41.     } 

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

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

  1. data: some data here\n\n 

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

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

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

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

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


實時消息部分到此結(jié)束。我想說的是,這就是后端的全部內(nèi)容。但是為了編寫前端代碼,我將再增加一個登錄端點:一個僅用于開發(fā)的登錄。

 

 

責(zé)任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2020-10-09 12:45:19

創(chuàng)建消息即時消息編程語言

2019-09-29 15:25:13

CockroachDBGoJavaScript

2019-10-28 20:12:40

OAuthGuard中間件編程語言

2020-03-31 12:21:20

JSON即時消息編程語言

2020-10-12 09:20:13

即時消息Access頁面編程語言

2020-10-19 16:20:38

即時消息Conversatio編程語言

2020-10-16 14:40:20

即時消息Home頁面編程語言

2020-10-10 20:51:10

即時消息編程語言

2021-03-25 08:29:33

SpringBootWebSocket即時消息

2023-08-14 08:01:12

websocket8g用戶

2025-06-30 01:45:00

Netty輪詢HTTP 協(xié)議

2015-03-18 15:37:19

社交APP場景

2011-10-19 09:30:23

jQuery

2024-02-01 12:54:00

RustWebSocket消息代理

2023-11-30 08:34:29

批量消息消息隊列

2021-12-03 00:02:01

通訊工具即時

2010-05-24 09:51:37

System Cent

2023-03-27 08:33:32

2022-08-30 11:41:53

網(wǎng)絡(luò)攻擊木馬

2009-06-29 09:06:42

微軟Web版MSN
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产亚洲久 | 日韩av在线中文字幕 | 91av在线电影 | 久草视频观看 | 精品三级在线观看 | 最新高清无码专区 | 99久久99热这里只有精品 | 色综久久 | 日本三级全黄三级三级三级口周 | 国产黄视频在线播放 | 亚洲九九精品 | 中文字幕亚洲欧美日韩在线不卡 | 欧洲亚洲视频 | 91资源在线 | 国产一区二区在线免费观看 | 成人精品国产一区二区4080 | 亚洲欧美综合 | 精品国产黄色片 | 中文字幕综合 | 视频在线一区 | 免费观看黄a一级视频 | 欧美激情精品久久久久久免费 | 国产精品视频一二三区 | 九九免费视频 | 91视频电影 | 国产九九精品 | 成人一区二区电影 | 日本免费一区二区三区 | 日韩影音 | 伊人超碰在线 | 成人av播放 | 国产精品一区二区不卡 | 国产精品国产成人国产三级 | 91国在线视频 | 自拍偷拍欧美 | 亚洲国产欧美一区二区三区久久 | 人人干在线视频 | 成人av一区 | 国产精品久久久乱弄 | 精品国产一区二区三区久久 | 久久综合久久久 |