HTML5 Server-Sent Events (SSE) 是一种技术,它允许服务器向浏览器推送更新。与传统的轮询不同,SSE提供了真正的单向实时通信通道:服务器可以主动发送数据到客户端,而不需要客户端发起请求。这对于实现实时更新的应用非常有用,比如股票行情、社交网络更新、聊天应用等。
SSE 的特点
- 单向通信:服务器到客户端的通信是单向的,客户端不能通过同一个连接向服务器发送信息。
- 自动重连:如果连接断开,浏览器会自动尝试重新建立连接。
- 简单性:相比WebSocket,SSE更简单,因为它基于HTTP协议,并且不需要额外的握手过程。
- 事件驱动:服务器可以通过发送特定格式的消息来触发客户端上的事件处理函数。
SSE 的基本语法
服务器端
服务器需要设置正确的HTTP响应头,并使用特定的格式发送消息给客户端:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
data: This is a message\n\n
每个消息以data:
开头,后面跟着消息内容,最后用两个换行符(\n\n
)结束。此外,还可以发送其他类型的指令,如event:
指定事件类型或id:
设置事件ID。
客户端
在客户端,使用JavaScript中的EventSource
对象来接收来自服务器的消息:
if(typeof(EventSource)!=="undefined") {
var source = new EventSource("/events");
source.onmessage = function(event) {
console.log("New message:", event.data);
};
source.onerror = function(event) {
console.error("Error occurred:", event);
};
} else {
console.log("Your browser does not support server-sent events.");
}
示例:
下面是五个使用HTML5 Server-Sent Events (SSE) 从Gin框架中获取信息的完整示例,每个示例展示了不同的应用场景。这些示例包括了从简单的计数器更新到更复杂的实时通知系统和动态数据推送。
示例1: 简单计数器更新
服务器端(Go + Gin)代码:
文件:main.go
package main
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 加载HTML模板文件夹中的所有HTML文件,以便可以在响应中使用这些模板。
// 这里假设HTML文件位于项目根目录下的"templates"文件夹中。
r.LoadHTMLGlob("templates/*")
// 定义根路径"/"的GET请求处理器。
// 当用户访问根URL时,将渲染并返回"index.html"模板。
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
// 定义处理SSE事件的GET请求处理器,路径为"/events"。
r.GET("/events", func(c *gin.Context) {
// 设置HTTP响应头以支持SSE。
// Content-Type设置为"text/event-stream"表示这是一个SSE流。
// Cache-Control设置为"no-cache"防止浏览器缓存数据。
// Connection设置为"keep-alive"保持连接打开。
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
// 检查ResponseWriter是否实现了Flusher接口,确保可以实时发送数据。
flusher, ok := c.Writer.(http.Flusher)
if !ok {
http.Error(c.Writer, "Streaming unsupported!", http.StatusInternalServerError)
return
}
// 开始一个循环来模拟服务器向客户端发送20条消息。
for i := 0; i < 20; i++ {
// 发送20条消息
// 构建要发送的消息,格式为"data: [message]\n\n"。
message := fmt.Sprintf("data: %d\n\n", i)
c.Writer.WriteString(message)
// 调用Flush()方法立即将缓冲区的数据发送给客户端。
flusher.Flush()
// 每次发送消息后暂停1秒,模拟延迟。
time.Sleep(time.Second)
// 如果客户端断开了连接(例如关闭了页面),则退出循环。
if c.Writer.Size() == 0 {
break
}
}
})
// 启动HTTP服务器,监听8080端口。
// Gin框架默认在0.0.0.0上监听,意味着可以从任何网络接口访问该服务。
r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
}
客户端(HTML + JavaScript)代码:
文件:templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 设置文档的字符编码为UTF-8 -->
<title>SSE Counter</title>
<!-- 设置页面标题 -->
</head>
<body>
<h1>Counter:</h1>
<!-- 显示计数器标题 -->
<p id="counter">0</p>
<!-- 显示计数器数值,初始值设置为0 -->
<script type="text/javascript">
// 检查浏览器是否支持Server-Sent Events (SSE)
if(typeof(EventSource)!=="undefined") {
// 创建一个新的EventSource对象,连接到服务器端点"/events"
var source = new EventSource("/events");
// 当从服务器接收到消息时触发此函数
source.onmessage = function(event) {
// 更新页面中ID为"counter"的<p>元素的内容为接收到的消息数据
document.getElementById("counter").innerHTML = event.data;
};
// 如果发生错误(例如连接断开),触发此函数
source.onerror = function(event) {
console.error("