重庆铜梁网站建设报价,弹窗广告投放平台,网站建设策划案,苏中建设南京区域公司HTML5 Server-Sent Events (SSE) 是一种技术#xff0c;它允许服务器向浏览器推送更新。与传统的轮询不同#xff0c;SSE提供了真正的单向实时通信通道#xff1a;服务器可以主动发送数据到客户端#xff0c;而不需要客户端发起请求。这对于实现实时更新的应用非常有用它允许服务器向浏览器推送更新。与传统的轮询不同SSE提供了真正的单向实时通信通道服务器可以主动发送数据到客户端而不需要客户端发起请求。这对于实现实时更新的应用非常有用比如股票行情、社交网络更新、聊天应用等。
SSE 的特点
单向通信服务器到客户端的通信是单向的客户端不能通过同一个连接向服务器发送信息。自动重连如果连接断开浏览器会自动尝试重新建立连接。简单性相比WebSocketSSE更简单因为它基于HTTP协议并且不需要额外的握手过程。事件驱动服务器可以通过发送特定格式的消息来触发客户端上的事件处理函数。
SSE 的基本语法
服务器端
服务器需要设置正确的HTTP响应头并使用特定的格式发送消息给客户端
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alivedata: 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 mainimport (fmtnet/httptimegithub.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 langen
headmeta charsetUTF-8!-- 设置文档的字符编码为UTF-8 --titleSSE Counter/title!-- 设置页面标题 --
/head
bodyh1Counter:/h1!-- 显示计数器标题 --p idcounter0/p!-- 显示计数器数值初始值设置为0 --script typetext/javascript// 检查浏览器是否支持Server-Sent Events (SSE)if(typeof(EventSource)!undefined) {// 创建一个新的EventSource对象连接到服务器端点/eventsvar source new EventSource(/events);// 当从服务器接收到消息时触发此函数source.onmessage function(event) {// 更新页面中ID为counter的p元素的内容为接收到的消息数据document.getElementById(counter).innerHTML event.data;};// 如果发生错误例如连接断开触发此函数source.onerror function(event) {console.error(Error occurred:, event);// 可选关闭事件源以防止进一步尝试重新连接// source.close();};} else {// 如果浏览器不支持SSE则显示提示信息document.getElementById(counter).innerHTML Sorry, your browser does not support server-sent events.;}/script!-- 该脚本块用于与服务器建立SSE连接并根据接收的数据更新页面上的计数器 --
/body
/html示例2: 实时通知系统
服务器端Go Gin代码:
文件main.go
package mainimport (fmtnet/httpsynctimegithub.com/gin-gonic/gin
)// 定义一个互斥锁用于在广播通知时同步对clients的访问。
var mu sync.Mutex// clients是一个保存所有客户端连接的映射键是客户端的通信信道值是一个布尔值表示状态。
var clients make(map[chan string]bool)// broadcastNotification向所有连接的客户端广播通知消息。
func broadcastNotification(msg string) {// 加锁以确保并发安全。mu.Lock()defer mu.Unlock()// 遍历所有客户端向它们发送消息。for client : range clients {client - msg}
}// handleEvents处理客户端的事件流请求保持连接开放并实时发送事件数据。
func handleEvents(c *gin.Context) {// 设置响应头指明这是一个事件流。c.Header(Content-Type, text/event-stream)c.Header(Cache-Control, no-cache)c.Header(Connection, keep-alive)// 创建一个信道用于向该客户端发送消息。clientChan : make(chan string)defer close(clientChan)// 加锁以确保并发安全。mu.Lock()clients[clientChan] truemu.Unlock()// 检查是否支持Flush操作。flusher, ok : c.Writer.(http.Flusher)if !ok {http.Error(c.Writer, Streaming unsupported!, http.StatusInternalServerError)return}// 启动一个goroutine监听clientChan并向客户端发送数据。go func() {for msg : range clientChan {c.Writer.WriteString(fmt.Sprintf(data: %s\n\n, msg))flusher.Flush()}}()// 保持连接开放定期检查客户端是否还在线。for {time.Sleep(time.Second)if _, err : c.Writer.Write([]byte{}); err ! nil {delete(clients, clientChan)break}}
}// main是程序的入口点初始化Gin框架并设置路由。
func main() {r : gin.Default()r.LoadHTMLGlob(templates/*)// 定义根路径/的GET请求处理器。// 当用户访问根URL时将渲染并返回index.html模板。r.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, index.html, nil)})// 定义/events的GET请求处理器用于处理事件流。r.GET(/events, handleEvents)// 启动一个goroutine定期生成通知消息并广播。go func() {for i : 0; ; i {time.Sleep(3 * time.Second)broadcastNotification(fmt.Sprintf(New Notification %d, i))}}()// 启动HTTP服务器监听8080端口。r.Run(:8080)
}
客户端HTML JavaScript代码:
文件templates/index.html
!DOCTYPE html
html langen
head
!-- 定义文档的字符编码 --
meta charsetUTF-8
!-- 设置网页的标题 --
titleReal-time Notifications/title
/head
body
!-- 显示通知列表的标题 --
h1Notifications:/h1
!-- 动态添加通知的容器 --
ul idnotifications/ulscript typetext/javascript
// 检查浏览器是否支持EventSource接口
if(typeof(EventSource)!undefined) {// 创建EventSource对象连接到服务器的事件流var source new EventSource(/events);// 监听来自服务器的消息事件source.onmessage function(event) {// 创建一个新的li元素来显示通知var li document.createElement(li);// 设置li元素的文本内容为接收到的消息数据li.textContent event.data;// 将新的通知添加到通知列表中document.getElementById(notifications).appendChild(li);};
} else {// 如果浏览器不支持EventSource显示提示信息document.write(Sorry, your browser does not support server-sent events.);
}
/script
/body
/html示例3: 动态天气更新
服务器端Go Gin代码:
文件main.go
package mainimport (fmtnet/httptimegithub.com/gin-gonic/gin
)// getWeatherData 获取天气数据。在实际应用中这个函数应该与天气服务API交互以获取实时数据。
// 返回值: 一个描述天气的字符串。
func getWeatherData() string {// 这里应该有一个函数来获取实际的天气数据return Sunny with a chance of meatballs.
}// main 是程序的入口点。它设置了一个Gin路由器配置了两个GET请求的处理器并启动了服务器。
func main() {r : gin.Default()r.LoadHTMLGlob(templates/*)// 定义根路径/的GET请求处理器。// 当用户访问根URL时将渲染并返回index.html模板。r.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, index.html, nil)})// 定义/weather路径的GET请求处理器。// 该处理器通过Server-Sent Events (SSE)每5分钟向客户端发送一次天气更新。r.GET(/weather, func(c *gin.Context) {c.Header(Content-Type, text/event-stream)c.Header(Cache-Control, no-cache)c.Header(Connection, keep-alive)flusher, ok : c.Writer.(http.Flusher)if !ok {http.Error(c.Writer, Streaming unsupported!, http.StatusInternalServerError)return}for {data : getWeatherData()c.Writer.WriteString(fmt.Sprintf(data: %s\n\n, data))flusher.Flush()time.Sleep(5 * time.Minute) // 每五分钟更新一次if c.Writer.Size() 0 {break}}})// 启动HTTP服务器监听8080端口。r.Run(:8080)
}
客户端HTML JavaScript代码:
文件templates/index.html
!DOCTYPE html
html langen
head
meta charsetUTF-8
titleDynamic Weather Updates/title
/head
body
h1Weather:/h1
p idweatherLoading.../pscript typetext/javascript
if(typeof(EventSource)!undefined) {var source new EventSource(/weather);source.onmessage function(event) {document.getElementById(weather).innerHTML event.data;};
} else {document.getElementById(weather).innerHTML Your browser does not support server-sent events.;
}
/script
/body
/html示例4: 聊天室消息推送
服务器端Go Gin代码:
文件main.go
package mainimport (fmtnet/httpsynctimegithub.com/gin-gonic/gin
)// messages 存储聊天消息。
var messages []string// mu 用于保护 messages 切片的并发访问安全。
var mu sync.Mutex// addMessage 向消息列表中添加新消息。
// 该函数通过 mu 锁确保并发安全。
func addMessage(msg string) {mu.Lock()defer mu.Unlock()messages append(messages, msg)
}func main() {r : gin.Default()r.LoadHTMLGlob(templates/*)// 定义根路径/的GET请求处理器。// 当用户访问根URL时将渲染并返回index.html模板。r.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, index.html, nil)})// 处理/chat的GET请求以Server-Sent Events(SSE)形式发送聊天消息。// 该处理器持续运行每秒向客户端推送一次消息直到连接关闭。r.GET(/chat, func(c *gin.Context) {c.Header(Content-Type, text/event-stream)c.Header(Cache-Control, no-cache)c.Header(Connection, keep-alive)flusher, ok : c.Writer.(http.Flusher)if !ok {http.Error(c.Writer, Streaming unsupported!, http.StatusInternalServerError)return}for {mu.Lock()msgs : messagesmu.Unlock()for _, msg : range msgs {c.Writer.WriteString(fmt.Sprintf(data: %s\n\n, msg))flusher.Flush()}time.Sleep(time.Second)if c.Writer.Size() 0 {break}}})// 处理/send的POST请求用于接收客户端发送的新消息。// 从请求中提取message字段并将其添加到消息列表中。r.POST(/send, func(c *gin.Context) {msg : c.PostForm(message)addMessage(msg)})// 启动HTTP服务器监听端口为8080。r.Run(:8080)
}
客户端HTML JavaScript代码:
文件templates/index.html
!DOCTYPE html
html langen
head
meta charsetUTF-8
titleChat Room/title
/head
body
h1Chat Room:/h1
ul idmessages/ul
form idchat-forminput typetext namemessage placeholderType a message... required /button typesubmitSend/button
/formscript typetext/javascript
// 检查浏览器是否支持EventSource
if(typeof(EventSource)!undefined) {// 创建EventSource实例建立到服务器的连接var source new EventSource(/chat);// 监听服务器发送的消息事件source.onmessage function(event) {// 创建一个新的li元素var li document.createElement(li);// 将服务器发送的数据设置为li元素的文本内容li.textContent event.data;// 将li元素添加到页面上的messages元素中document.getElementById(messages).appendChild(li);};// 监听表单的提交事件document.getElementById(chat-form).addEventListener(submit, function(event) {// 阻止默认的表单提交行为event.preventDefault();// 创建FormData实例用于处理表单数据var formData new FormData(event.target);// 使用fetch API发送POST请求到服务器fetch(/send, {method: POST,body: formData,}).then(response {// 如果服务器响应成功重置表单if (response.ok) {event.target.reset();}});});
} else {// 如果浏览器不支持EventSource显示提示信息document.write(Sorry, your browser does not support server-sent events.);
}
/script
/body
/html示例5: 实时股票价格更新
服务器端Go Gin代码:
文件main.go
package mainimport (fmtmath/randnet/httptimegithub.com/gin-gonic/gin
)// getRandomStockPrice 生成一个随机的股票价格。
// 假设股票价格在100到200之间。
func getRandomStockPrice() float64 {return rand.Float64()*100 100
}func main() {r : gin.Default()r.LoadHTMLGlob(templates/*)// 定义根路径/的GET请求处理器。// 当用户访问根URL时将渲染并返回index.html模板。r.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, index.html, nil)})// 处理/stock的GET请求通过Server-Sent Events (SSE) 实时推送股票价格。r.GET(/stock, func(c *gin.Context) {c.Header(Content-Type, text/event-stream)c.Header(Cache-Control, no-cache)c.Header(Connection, keep-alive)// 检查响应写入器是否支持flush操作。flusher, ok : c.Writer.(http.Flusher)if !ok {http.Error(c.Writer, Streaming unsupported!, http.StatusInternalServerError)return}// 创建一个定时器每10秒发送一次股票价格。ticker : time.NewTicker(10 * time.Second)defer ticker.Stop()for {select {case -ticker.C:// 生成新的股票价格并发送到客户端。price : getRandomStockPrice()c.Writer.WriteString(fmt.Sprintf(data: %.2f\n\n, price))flusher.Flush()// 如果响应内容为空则终止循环。if c.Writer.Size() 0 {return}}}})// 启动HTTP服务器监听端口8080。r.Run(:8080)
}
客户端HTML JavaScript代码:
文件templates/index.html
!DOCTYPE html
html langen
head
meta charsetUTF-8
titleLive Stock Price/title
/head
body
h1Stock Price:/h1
p idpriceLoading.../pscript typetext/javascript
if(typeof(EventSource)!undefined) {var source new EventSource(/stock);source.onmessage function(event) {document.getElementById(price).innerHTML $ event.data;};
} else {document.getElementById(price).innerHTML Your browser does not support server-sent events.;
}
/script
/body
/html这些示例涵盖了从简单到复杂的不同SSE应用场景。你可以根据自己的需求调整和扩展这些例子以适应特定的业务逻辑或功能要求。
测试代码下载
html5_api代码