Featured image of post sse

sse

一个gin 使用服务端推送的笔记

sse gin 的花式推送

众所周知ai llm 这些东西让SSE 这个技术传遍"石河子"东西南北

其实按照推送技术来说还是有不少的:

  • chunk 分块 这个其实是SSE 的基础
  • sse 服务端推送事件
  • websocket 这个可以支持双向的,但是无法兼容h2

代码示例

下面给一下处了 websocket 以外的 推送示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
func ChunkDemo(c *gin.Context) {
		w := c.Writer
		header := w.Header()
		header.Set("Transfer-Encoding", "chunked")
		header.Set("Content-Type", "text/html")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`
			<html>
					<body>
		`))
		w.(http.Flusher).Flush()
		for i := 0; i < 10; i++ {
			w.Write([]byte(fmt.Sprintf(`
				<h1>%d</h1>
			`, i)))
			w.(http.Flusher).Flush()
			time.Sleep(time.Duration(1) * time.Second)
		}
		w.Write([]byte(`
			
					</body>
			</html>
		`))
		w.(http.Flusher).Flush()
	})
// h1 sse
func sseHandlerHTTP1(c *gin.Context) {
    // 设置响应头
    c.Writer.Header().Set("Content-Type", "text/event-stream")
    c.Writer.Header().Set("Cache-Control", "no-cache")
    c.Writer.Header().Set("Connection", "keep-alive")
    c.Writer.Header().Set("Access-Control-Allow-Origin", "*")

    // 确保响应头被立即发送
    c.Writer.(http.Flusher).Flush()

    ticker := time.NewTicker(2 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-c.Request.Context().Done():
            return
        case t := <-ticker.C:
            // 发送SSE消息
            c.Writer.Write([]byte("data: " + t.Format(time.RFC3339) + "\n\n"))
            c.Writer.(http.Flusher).Flush()
        }
    }
}
func sseHandlerHTTP2(c *gin.Context) {
    // 设置响应头
    c.Writer.Header().Set("Content-Type", "text/event-stream")
    c.Writer.Header().Set("Access-Control-Allow-Origin", "*")

    // 确保响应头被立即发送
    c.Writer.(http.Flusher).Flush()

    ticker := time.NewTicker(2 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-c.Request.Context().Done():
            return
        case t := <-ticker.C:
            // 发送SSE消息
            c.Writer.Write([]byte("data: " + t.Format(time.RFC3339) + "\n\n"))
            c.Writer.(http.Flusher).Flush()
        }
    }
}

上面的区别其实是 h2 不用设置客户端缓存控制这个响应头, 比较统一的是推送开始和结束都需要Flush 刷写一下

Licensed under CC BY-NC-SA 4.0
往日已经不在,未来尚未开始
使用 Hugo 构建
主题 StackJimmy 设计