SSE

需求

当需要让服务端向客户端发送消息的时候

比如实时更新状态或推荐内容

相比websocket消耗资源更少,而且建立连接更方便,自带重传机制,不需要像websocket一样需要自己实现重传机制

参考资料

https://zh.javascript.info/server-sent-events

https://www.apiseven.com/blog/what-is-sse

服务端:

package main

import (
	"net/http"
	"time"
)

func serveEvents(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/event-stream")
	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Connection", "keep-alive")
	w.Header().Set("Access-Control-Allow-Origin", "*")

	flusher, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, "Streaming not supported", http.StatusInternalServerError)
		return
	}

	ctx := r.Context()

	// 发送一次性 `retry` 字段
	_, _ = w.Write([]byte("retry: 1000\n\n"))
	flusher.Flush()

	for {
		select {
		case <-ctx.Done():
			return
		default:
			// 发送自定义事件
			event := "event: timeUpdate\n"
			data := "data: " + time.Now().Format(time.RFC3339) + "\n\n"
			data2 := "data: " + "hello, I'm data2" + "\n\n"
			_, err := w.Write([]byte(event + data + data2))
			if err != nil {
				break
			}
			flusher.Flush()
			time.Sleep(2 * time.Second)
		}
	}
}

func main() {
	http.HandleFunc("/events", serveEvents)
	http.ListenAndServe(":8080", nil)
}


客户端:

<!DOCTYPE html>
<html>
<head>
    <title>SSE Client</title>
</head>
<body>
<div id="events"></div>
<script>
    var source = new EventSource("http://localhost:8080/events");

    // 监听自定义事件
    source.addEventListener("timeUpdate", function(event) {
        var eventsDiv = document.getElementById('events');
        var newElement = document.createElement("p");
        newElement.textContent = "Time Update: " + event.data;
        eventsDiv.appendChild(newElement);
    });

    // 监听默认的 message 事件
    source.onmessage = function(event) {
        var eventsDiv = document.getElementById('events');
        var newElement = document.createElement("p");
        newElement.textContent = "Received: " + event.data;
        eventsDiv.appendChild(newElement);
    };

    // 监听错误事件
    source.onerror = function(err) {
        console.error("EventSource failed:", err);
    };
</script>
</body>
</html>

效果:

实现了断开以后自动重新请求,服务恢复后会继续获取信息