当前位置: 首页 > article >正文

用Go实现 SSE 实时推送消息(消息通知)——思悟项目技术4

目录

简介

工作原理

例子

使用场景


简介

SSE(Server - Sent Events)是一种允许服务器向客户端实时推送更新的 Web 技术。是一种基于 HTTP 协议的单向通信机制,服务器可以在客户端建立连接后,持续不断地向客户端发送事件流。客户端只需发起一次请求,服务器就能随时向客户端推送新的数据,无需客户端反复请求。

工作原理

  1. 客户端发起请求:客户端通过创建一个 EventSource 对象(在浏览器环境中)向服务器发起一个 HTTP 请求,请求的响应头中 Content - Type 为 text/event - stream。
  2. 服务器建立连接:服务器接收到请求后,与客户端建立长连接,保持连接处于打开状态。
  3. 服务器推送数据:服务器可以在有新数据时,将数据以特定的格式(事件流格式)发送给客户端。事件流由多个事件组成,每个事件包含事件类型、数据等信息。
  4. 客户端接收数据:客户端的 EventSource 对象会持续监听服务器发送的事件流,当接收到新事件时,会触发相应的事件处理函数。

    例子

    后端(Go + Gin):

    POST /send 端点是用于接收前端发送的消息并广播到所有 SSE 客户端,它的作用是触发消息的推送。

    而 for msg := range client 这部分代码是具体执行消息推送的逻辑,它确保 SSE 连接的客户端能够实时收到消息。

    package main
    
    import (
        "fmt"
        "net/http"
        "sync"
        "time"
    
        "github.com/gin-gonic/gin"
    )
    
    type Client chan string
    
    var (
        clients   = make(map[Client]bool) // 记录所有 SSE 连接
        clientsMu sync.Mutex              // 保护 clients 并发访问
    )
    
    func main() {
        r := gin.Default()
    
        // SSE 端点:用于客户端接收推送
        r.GET("/stream", func(c *gin.Context) {
           client := make(Client, 10) // 创建一个带缓冲的通道
           clientsMu.Lock()
           clients[client] = true // 添加新客户端
           clientsMu.Unlock()
    
           // 设置 SSE 头部
           c.Header("Content-Type", "text/event-stream")
           c.Header("Cache-Control", "no-cache")
           c.Header("Connection", "keep-alive")
    
           // 监听消息通道
           // 监听 SSE(Server-Sent Events) 连接的消息通道,并将新消息推送到客户端。它实现了 服务器端的推送机制。
           for msg := range client {
              fmt.Fprintf(c.Writer, "data: %s\n\n", msg)
              c.Writer.Flush()
           }
        })
    
        // 发送消息端点:接收前端消息,并推送给所有客户端
        r.POST("/send", func(c *gin.Context) {
           var json struct {
              Message string `json:"message"`
           }
           if err := c.ShouldBindJSON(&json); err != nil {
              c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
              return
           }
    
           // 发送消息到所有 SSE 客户端
           broadcast(json.Message)
           c.JSON(http.StatusOK, gin.H{"status": "sent"})
        })
    
        r.GET("/", func(c *gin.Context) {
           c.Header("Content-Type", "text/html")
           c.String(http.StatusOK, htmlContent)
        })
    
        r.Run(":8080")
    }
    
    // 发送消息给所有已连接的 SSE 客户端
    func broadcast(message string) {
        clientsMu.Lock()
        defer clientsMu.Unlock()
        for client := range clients {
           select {
           case client <- fmt.Sprintf("%s - %s", message, time.Now().Format("15:04:05")):
           default:
              close(client)           // 关闭不可用的客户端
              delete(clients, client) // 从列表中移除
           }
        }
    }
    
    const htmlContent = `<!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>SSE 实时消息</title>
    </head>
    <body>
        <h2>Server-Sent Events (SSE) 消息推送</h2>
        <input type="text" id="messageInput" placeholder="输入消息">
        <button onclick="sendMessage()">发送消息</button>
        <h3>收到的消息:</h3>
        <div id="messages"></div>
    
        <script>
            // 监听 SSE 事件
            const eventSource = new EventSource("/stream");
            eventSource.onmessage = function(event) {
                const div = document.createElement("div");
                div.textContent = "收到:" + event.data;
                document.getElementById("messages").appendChild(div);
            };
    
            // 发送消息到后端
            function sendMessage() {
                const message = document.getElementById("messageInput").value;
                if (!message) return;
    
                fetch("/send", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ message: message })
                }).then(response => response.json())
                  .then(data => console.log("消息已发送:", data));
            }
        </script>
    </body>
    </html>`

    结果:

    使用场景

    • 实时新闻更新:新闻网站可以使用 SSE 实时向用户推送最新的新闻消息。
    • 股票行情推送:金融类应用可以利用 SSE 实时更新股票价格、交易信息等。
    • 在线聊天系统的消息通知:当有新消息时,服务器可以及时将消息推送给客户端。


    http://www.kler.cn/a/540794.html

    相关文章:

  • 攻防世界33 catcat-new【文件包含/flask_session伪造】
  • JavaScript 中的防抖和节流,它们的区别是什么,以及如何实现?
  • Linux 安装 Ollama
  • [前端]CRX持久化
  • 采用分步式无线控制架构实现水池液位自动化管理
  • 深入探究 Rust 测试:灵活控制测试的执行方式
  • 绘制中国平安股价的交互式 K 线图
  • 31、spark-on-kubernetes中任务报错No space left on device
  • Fastadmin根据链接参数显示不同列表格
  • 10 FastAPI 的自动文档
  • OpenAI 实战进阶教程 - 第十二节 : 多模态任务开发(文本、图像、音频)
  • 持续集成-笔记
  • DeepSeek之于心理学的一点思考
  • Java中有100万个对象,用list map泛型存储和用list对象泛型存储,那个占用空间大,为什么...
  • python两段多线程的例子
  • 网络安全架构分层 网络安全组织架构
  • 什么是蒸馏大型语言模型
  • WiFi配网流程—SmartConfig 配网流程
  • 基于uniapp vue3 的滑动抢单组件
  • Markdown+Vscode+Mindmaster打造读书笔记
  • C# Mutex 锁 使用详解
  • 爬虫案例-爬取某度文档利用飞桨ch_pp-ocrv3模型提高对图片的识别
  • [小白入门]PostgreSQL too many clients already
  • 轻松掌握:滤波器截止频率计算
  • 蓝桥杯C语言组:博弈问题
  • PL/SQL语言的云计算