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>
效果:
实现了断开以后自动重新请求,服务恢复后会继续获取信息