go語言如何使用gin庫實現(xiàn)SSE長連接
前言
項目需求:在go項目中實現(xiàn)SSE長連接,耗時操作完成后,后端主動通知前端消息。
1.建立長連接
最主要的操作是修改請求中的Content-Type類型為"text/event-stream"。
需要注意幾點,后端首先不能讓請求處理代碼跑完,如果跑完這個請求就會斷掉,保存的*gin.Context信息也就沒用了,因此要新建一個range chan維持處理狀態(tài)。
另外這里如果用for循環(huán)代替chan,會導致前端持續(xù)發(fā)送請求到后端。
import ( "encoding/json" "fmt" "github.com/gin-gonic/gin" "github.com/labstack/gommon/log" "net/http" "strings" "time" ) var ifChannelsMapInit = false var channelsMap = map[string]chan string{} func initChannelsMap() { channelsMap = make(map[string]chan string) } func AddChannel(userEmail string, traceId string) { if !ifChannelsMapInit { initChannelsMap() ifChannelsMapInit = true } var newChannel = make(chan string) channelsMap[userEmail+traceId] = newChannel log.Infof("Build SSE connection for user = " + userEmail + ", trace id = " + traceId) } func BuildNotificationChannel(userEmail string, traceId string, c *gin.Context) { AddChannel(userEmail, traceId) c.Writer.Header().Set("Content-Type", "text/event-stream") c.Writer.Header().Set("Cache-Control", "no-cache") c.Writer.Header().Set("Connection", "keep-alive") w := c.Writer flusher, _ := w.(http.Flusher) closeNotify := c.Request.Context().Done() go func() { <-closeNotify delete(channelsMap, userEmail+traceId) log.Infof("SSE close for user = " + userEmail + ", trace id = " + traceId) return }() fmt.Fprintf(w, "data: %s\n\n", "--ping--") flusher.Flush() for msg := range channelsMap[userEmail+traceId] { fmt.Fprintf(w, "data: %s\n\n", msg) flusher.Flush() } }
2.后端主動通知前端消息
當耗時操作處理完成后,調(diào)用該方法,前端會收到通知。
func SendNotification(userEmail string, messageBody string, actionType string) { log.Infof("Send notification to user = " + userEmail) var msg = dao.NotificationLog{} msg.MessageBody = messageBody msg.UserEmail = userEmail msg.Type = actionType msg.Status = UNREAD msg.CreateTime = time.Now() msg.Create() msgBytes, _ := json.Marshal(msg) for key := range channelsMap { if strings.Contains(key, userEmail) { channel := channelsMap[key] channel <- string(msgBytes) } } }
3.調(diào)試
準備兩個接口,分別是建立SSE和觸發(fā)耗時操作
GroupV1Rest.GET("/notification/socket-connection", controllers.SocketConnection) GroupV1Rest.GET("/notification/export-excel", controllers.ExportExcel)
打開瀏覽器,進入調(diào)試模式,在console頁輸入
e = new EventSource('/business/v1/notification/socket-connection'); e.onmessage = function(event) { console.log(event.data); };
看到日志打印‘--ping--’,長連接已建立
此時發(fā)送第二個請求,調(diào)試模式看到通知被chan處理
返回瀏覽器,可以看到已經(jīng)收到通知
4.關(guān)閉長連接
前端關(guān)閉頁面后,自動觸發(fā)監(jiān)聽事件,后端清理連接信息
總結(jié)
到此這篇關(guān)于go語言如何使用gin庫實現(xiàn)SSE長連接的文章就介紹到這了,更多相關(guān)go實現(xiàn)SSE長連接內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言中函數(shù)可變參數(shù)(Variadic Parameter)詳解
在Python中,在函數(shù)參數(shù)不確定數(shù)量的情況下,可以動態(tài)在函數(shù)內(nèi)獲取參數(shù)。在Go語言中,也有類似的實現(xiàn)方式,本文就來為大家詳細講解一下2022-07-07golang如何通過viper讀取config.yaml文件
這篇文章主要介紹了golang通過viper讀取config.yaml文件,圍繞golang讀取config.yaml文件的相關(guān)資料展開詳細內(nèi)容,需要的小伙伴可以參考一下2022-03-03Golang實現(xiàn)Redis網(wǎng)絡協(xié)議實例探究
這篇文章主要為大家介紹了Golang實現(xiàn)Redis網(wǎng)絡協(xié)議實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01