我们都知道,想实现浏览器和服务器互相推送消息,可以使用 websocket 协议。

但如果只想实现浏览器推送消息给客户端,我们还可以选择 SSE 协议,它其实是基于 HTTP 的一种协议。

SSE,服务器发送事件(Server-sent events)

至于它是怎么基于 HTTP 来实现的呢?说理论太枯燥,我们直接看 Go 代码:

(要了解理论的去看我引用的文章)

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
package main

import (
"fmt"
"github.com/gin-gonic/gin"
"gopkg.in/antage/eventsource.v1"
"log"
"net/http"
)

func main() {
es := eventsource.New(nil, nil)
defer es.Close()
r := gin.Default()

{
r.GET("/events", esSSE)
r.Run(":8080")
}
}

func esSSE(c *gin.Context) {
w := c.Writer

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", "*")

_, ok := w.(http.Flusher)

if !ok {
log.Panic("server not support") //浏览器不兼容
}

_, err := fmt.Fprintf(w, "data: %s\n\n", "dsdf")
if err != nil {
return
}
}

这里的核心代码就在于 Header 的设置,比如 w.Header().Set("Content-Type", "text/event-stream")

只需要前端也做出相应的适配。SSE 其实就完成了。

这里我顺便也贴一个纯 html 的 Demo 吧

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
<!DOCTYPE html>
<html>
<head>
<title>SSE test</title>
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function () {
var evsrc = new EventSource("http://localhost:8080/events");
evsrc.onmessage = function (ev) {
document.getElementById("log")
.insertAdjacentHTML("beforeend", "<li>" + ev.data + "</li>");
}
evsrc.onerror = function (ev) {
console.log("readyState = " + ev.currentTarget.readyState);
}
})
</script>
</head>
<body>
<h1>SSE test</h1>
<div>
<ul id="log">
</ul>
</div>
</body>
</html>