当前位置:   article > 正文

go语言使用gin库实现SSE长连接_gin sse

gin sse

目录

1.建立长连接

2.后端主动通知前端消息

3.调试

4.关闭长连接 


项目需求:在go项目中实现SSE长连接,耗时操作完成后,后端主动通知前端消息。

1.建立长连接

最主要的操作是修改请求中的Content-Type类型为"text/event-stream"。

需要注意几点,后端首先不能让请求处理代码跑完,如果跑完这个请求就会断掉,保存的*gin.Context信息也就没用了,因此要新建一个range chan维持处理状态。

另外这里如果用for循环代替chan,会导致前端持续发送请求到后端。

  1. import (
  2. "encoding/json"
  3. "fmt"
  4. "github.com/gin-gonic/gin"
  5. "github.com/labstack/gommon/log"
  6. "net/http"
  7. "strings"
  8. "time"
  9. )
  10. var ifChannelsMapInit = false
  11. var channelsMap = map[string]chan string{}
  12. func initChannelsMap() {
  13. channelsMap = make(map[string]chan string)
  14. }
  15. func AddChannel(userEmail string, traceId string) {
  16. if !ifChannelsMapInit {
  17. initChannelsMap()
  18. ifChannelsMapInit = true
  19. }
  20. var newChannel = make(chan string)
  21. channelsMap[userEmail+traceId] = newChannel
  22. log.Infof("Build SSE connection for user = " + userEmail + ", trace id = " + traceId)
  23. }
  24. func BuildNotificationChannel(userEmail string, traceId string, c *gin.Context) {
  25. AddChannel(userEmail, traceId)
  26. c.Writer.Header().Set("Content-Type", "text/event-stream")
  27. c.Writer.Header().Set("Cache-Control", "no-cache")
  28. c.Writer.Header().Set("Connection", "keep-alive")
  29. w := c.Writer
  30. flusher, _ := w.(http.Flusher)
  31. closeNotify := c.Request.Context().Done()
  32. go func() {
  33. <-closeNotify
  34. delete(channelsMap, userEmail+traceId)
  35. log.Infof("SSE close for user = " + userEmail + ", trace id = " + traceId)
  36. return
  37. }()
  38. fmt.Fprintf(w, "data: %s\n\n", "--ping--")
  39. flusher.Flush()
  40. for msg := range channelsMap[userEmail+traceId] {
  41. fmt.Fprintf(w, "data: %s\n\n", msg)
  42. flusher.Flush()
  43. }
  44. }

2.后端主动通知前端消息

当耗时操作处理完成后,调用该方法,前端会收到通知。

  1. func SendNotification(userEmail string, messageBody string, actionType string) {
  2. log.Infof("Send notification to user = " + userEmail)
  3. var msg = dao.NotificationLog{}
  4. msg.MessageBody = messageBody
  5. msg.UserEmail = userEmail
  6. msg.Type = actionType
  7. msg.Status = UNREAD
  8. msg.CreateTime = time.Now()
  9. msg.Create()
  10. msgBytes, _ := json.Marshal(msg)
  11. for key := range channelsMap {
  12. if strings.Contains(key, userEmail) {
  13. channel := channelsMap[key]
  14. channel <- string(msgBytes)
  15. }
  16. }
  17. }

3.调试

准备两个接口,分别是建立SSE和触发耗时操作

  1. GroupV1Rest.GET("/notification/socket-connection", controllers.SocketConnection)
  2. GroupV1Rest.GET("/notification/export-excel", controllers.ExportExcel)

打开浏览器,进入调试模式,在console页输入

  1. e = new EventSource('/business/v1/notification/socket-connection');
  2. e.onmessage = function(event) {
  3. console.log(event.data);
  4. };

看到日志打印‘--ping--’,长连接已建立

 此时发送第二个请求,调试模式看到通知被chan处理

返回浏览器,可以看到已经收到通知

4.关闭长连接 

前端关闭页面后,自动触发监听事件,后端清理连接信息

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/962603
推荐阅读
相关标签
  

闽ICP备14008679号