一架梯子,一头程序猿,仰望星空!
Go Fiber教程 > 内容正文

Go Fiber Server-Sent Events (SSE) 例子


Server-Sent Events (SSE) 介绍

服务器发送事件(SSE)是一种服务器推送技术,可使客户端通过 HTTP 连接接收来自服务器的自动更新,它描述了服务器如何在建立初始客户端连接后向客户端发起数据传输。它们通常用于向浏览器客户端发送消息更新或连续数据流,其设计目的是通过名为 EventSource 的 JavaScript API 增强本地跨浏览器流,客户端可通过该 API 请求特定 URL 以接收事件流。作为 HTML5的一部分,WHATWG 对 EventSource API 进行了标准化。SSE 的媒体类型是文本/事件流。

提示:SSE跟Websocket最大的区别就是,SSE是服务端单向给客户端推送消息,Websocket是双向推送消息,有时候业务没那么复杂只要SSE单向推送消息即可,类似ChatGPT的AI对话使用的就是SSE技术。

Fiber SSE例子

package main

import (
    "bufio"
    "fmt"
    "log"
    "time"

    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/cors"
    "github.com/valyala/fasthttp"
)

// 模拟HTML客户端,这里实现前端js接收后端推送消息的例子,实际业务场景让前端写
var index = []byte(`<!DOCTYPE html>
<html>
<body>

<h1>SSE Messages</h1>
<div id="result"></div>

<script>
if(typeof(EventSource) !== "undefined") {
  var source = new EventSource("http://127.0.0.1:3000/sse");
  source.onmessage = function(event) {
    document.getElementById("result").innerHTML += event.data + "<br>";
  };
} else {
  document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>

</body>
</html>
`)

func main() {
    // Fiber 实例
    app := fiber.New()

    // CORS 限制,允许任意域名访问
    app.Use(cors.New(cors.Config{
        AllowOrigins:     "*",
        AllowHeaders:     "Cache-Control",
        AllowCredentials: true,
    }))

    // 访问 / 路径,我们先返回前端页面,让前端请求后端开始SSE消息推送
    app.Get("/", func(c *fiber.Ctx) error {
        c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8)

        return c.Status(fiber.StatusOK).Send(index)
    })

    // sse消息推送地址
    app.Get("/sse", func(c *fiber.Ctx) error {
        // 设置sse http头,注意Content-Type
        c.Set("Content-Type", "text/event-stream")
        c.Set("Cache-Control", "no-cache")
        c.Set("Connection", "keep-alive")
        c.Set("Transfer-Encoding", "chunked")

        // 开始推送消息
        c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
            fmt.Println("WRITER")
            var i int
            // 模拟循环向客户端推送消息
            for {
                i++
                msg := fmt.Sprintf("%d - the time is %v", i, time.Now())
                // 通过writer,借助Fprintf函数往客户端推送消息,实际业务场景,可以发送json文本,方便前端处理
                fmt.Fprintf(w, "data: Message: %s\n\n", msg)
                fmt.Println(msg)

                // 刷新输出数据,推向客户端
                err := w.Flush()
                if err != nil {
                    // Refreshing page in web browser will establish a new
                    // SSE connection, but only (the last) one is alive, so
                    // dead connections must be closed here.
                    fmt.Printf("Error while flushing: %v. Closing http connection.\n", err)

                    break
                }
                time.Sleep(2 * time.Second)
            }
        }))

        return nil
    })

    // Start server
    log.Fatal(app.Listen(":3000"))
}