Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn)
前言
在現(xiàn)代Web開(kāi)發(fā)中,前后端分離已成為主流趨勢(shì)。為了實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送,Server-Sent Events (SSE) 是一種高效且易于實(shí)現(xiàn)的技術(shù)。本文將介紹如何在Go語(yǔ)言中實(shí)現(xiàn)SSE服務(wù)端,并在前端使用JavaScript進(jìn)行集成,實(shí)現(xiàn)一個(gè)完整的實(shí)時(shí)數(shù)據(jù)推送系統(tǒng)
1. SSE簡(jiǎn)介
Server-Sent Events (SSE) 是HTML5的一項(xiàng)技術(shù),用于服務(wù)器向?yàn)g覽器自動(dòng)發(fā)送更新信息。SSE的主要特點(diǎn)包括:
- 單向通信:數(shù)據(jù)流是從服務(wù)器到客戶(hù)端的單向流動(dòng)。
- 自動(dòng)重連:如果連接斷開(kāi),客戶(hù)端會(huì)自動(dòng)嘗試重新建立連接。
- 簡(jiǎn)單易用:相比WebSocket,SSE的API更簡(jiǎn)單,更容易上手。
- 文本格式:SSE的數(shù)據(jù)是以文本形式發(fā)送的,通常為JSON或純文本。
2. 后端實(shí)現(xiàn)
2.1 設(shè)置靜態(tài)文件目錄
首先,我們需要設(shè)置靜態(tài)文件目錄,以便前端頁(yè)面和其他靜態(tài)資源可以被正確加載。
package main
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
func main() {
// 設(shè)置靜態(tài)文件目錄
fs := http.FileServer(http.Dir("./static"))
http.Handle("/", fs)
// 設(shè)置 SSE 處理器
http.HandleFunc("/events", handleEvents)
// 啟動(dòng)服務(wù)器
http.ListenAndServe(":8080", nil)
}2.2 設(shè)置SSE處理器
接下來(lái),我們創(chuàng)建一個(gè)SSE處理器來(lái)處理客戶(hù)端的SSE請(qǐng)求,并設(shè)置正確的響應(yīng)頭。
func handleEvents(w http.ResponseWriter, r *http.Request) {
// 設(shè)置 CORS 頭部
//w.Header().Set("Access-Control-Allow-Origin", "*")
//w.Header().Set("Access-Control-Allow-Methods", "GET")
//w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
// 設(shè)置響應(yīng)頭
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// 模擬數(shù)據(jù)流
for {
// 生成推送消息
data, _ := json.Marshal(map[string]string{"timestamp": time.Now().Format(time.RFC3339)})
_, err := fmt.Fprintf(w, "data: %s\n\n", data)
if err != nil {
// 客戶(hù)端斷開(kāi)連接,輸出日志
fmt.Println("Client disconnected:", err)
return
}
// 刷新緩沖區(qū)
if flusher, ok := w.(http.Flusher); ok {
flusher.Flush()
}
// 檢查是否應(yīng)該關(guān)閉連接
select {
case <-r.Context().Done():
return
default:
time.Sleep(2 * time.Second) // 每2秒發(fā)送一次消息
}
}
}2.3 啟動(dòng)HTTP服務(wù)器
在上面的代碼中,我們定義了兩個(gè)路由:
- /:處理靜態(tài)文件請(qǐng)求。
- /events:處理SSE請(qǐng)求。
3. 前端實(shí)現(xiàn)
3.1 創(chuàng)建前端頁(yè)面
創(chuàng)建一個(gè)名為 index.html 的文件,用于展示接收到的消息。將該文件放在 main.go 同級(jí)地 static 目錄下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE 案例</title>
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background-color: #f0f0f0;
}
.container {
text-align: center;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 100%;
box-sizing: border-box;
}
h1 {
color: #333;
margin-bottom: 20px;
}
#messages {
height: 300px; /* 固定高度 */
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
background-color: #f9f9f9;
color: #555;
margin-top: 20px;
box-sizing: border-box;
}
p {
margin: 5px 0;
font-size: 16px;
}
#clock {
font-size: 18px;
color: #777;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>服務(wù)器發(fā)送事件示例</h1>
<div id="messages"></div>
<div id="clock"></div>
</div>
<script>
// 創(chuàng)建一個(gè)新的 EventSource 實(shí)例
const eventSource = new EventSource('/events');
// 監(jiān)聽(tīng)消息事件
eventSource.onmessage = function (event) {
const newMessage = document.createElement('p');
newMessage.textContent = 'New message: ' + event.data;
document.getElementById('messages').appendChild(newMessage);
// 滾動(dòng)到底部
const messagesDiv = document.getElementById('messages');
messagesDiv.scrollTop = messagesDiv.scrollHeight;
};
// 監(jiān)聽(tīng)錯(cuò)誤事件
eventSource.onerror = function (error) {
console.error('EventSource failed:', error);
eventSource.close();
};
</script>
</body>
</html>
- 創(chuàng)建EventSource對(duì)象:const eventSource = new EventSource('/events'); 創(chuàng)建一個(gè)EventSource對(duì)象,連接到服務(wù)器的 /events 路由。
- 處理消息:eventSource.onmessage 事件處理器用于處理從服務(wù)器接收到的消息,并將其顯示在頁(yè)面上。
- 處理錯(cuò)誤:eventSource.onerror 事件處理器用于處理連接錯(cuò)誤,并在發(fā)生錯(cuò)誤時(shí)關(guān)閉連接。
- 自動(dòng)滾動(dòng):每次接收到新消息時(shí),自動(dòng)滾動(dòng)到消息列表的底部,確保用戶(hù)始終能看到最新的消息。
4. 運(yùn)行項(xiàng)目
4.1 啟動(dòng)服務(wù):
go run main.go
打開(kāi)瀏覽器,訪問(wèn) http://localhost:8080,你應(yīng)該能看到每?jī)擅腌姀姆?wù)器推送的一條新消息,且頁(yè)面內(nèi)容全屏自適應(yīng),樣式更加美觀。

5 注意事項(xiàng)
5.1 客戶(hù)端連接限制
- 瀏覽器對(duì)每個(gè)域名下的SSE連接數(shù)有限制。大多數(shù)現(xiàn)代瀏覽器允許每個(gè)域名最多6個(gè)并發(fā)連接。如果超過(guò)這個(gè)限制,新的連接將會(huì)被阻塞,直到有連接關(guān)閉。
- 如果你的應(yīng)用需要支持更多的并發(fā)連接,可以考慮使用子域名或負(fù)載均衡來(lái)分散連接。
5.2 服務(wù)器資源管理
- 每個(gè)SSE連接都會(huì)占用服務(wù)器的一個(gè)goroutine,因此需要合理管理服務(wù)器資源。如果預(yù)期會(huì)有大量并發(fā)連接,建議使用連接池或其他資源管理機(jī)制。
- 可以通過(guò)設(shè)置超時(shí)、心跳檢測(cè)等方式來(lái)管理長(zhǎng)時(shí)間未活動(dòng)的連接,避免資源浪費(fèi)。
5.3 錯(cuò)誤處理和重連
- 客戶(hù)端可以通過(guò) onerror 事件處理器來(lái)處理連接錯(cuò)誤,并實(shí)現(xiàn)自動(dòng)重連邏輯。
- 服務(wù)器端可以在連接關(guān)閉時(shí)發(fā)送適當(dāng)?shù)腻e(cuò)誤信息,幫助客戶(hù)端更好地處理異常情況。
5.4 安全性
- 確保SSE接口的安全性,避免暴露敏感數(shù)據(jù)??梢允褂肏TTPS來(lái)加密傳輸數(shù)據(jù)。
- 對(duì)于需要認(rèn)證的場(chǎng)景,可以在SSE請(qǐng)求中攜帶認(rèn)證信息,例如使用HTTP頭部或Cookie。
總結(jié)
本文詳細(xì)介紹了如何在Go語(yǔ)言中實(shí)現(xiàn)SSE(Server-Sent Events)服務(wù)端,并在前端使用JavaScript進(jìn)行集成,實(shí)現(xiàn)一個(gè)完整的實(shí)時(shí)數(shù)據(jù)推送系統(tǒng)。SSE作為一種輕量級(jí)的實(shí)時(shí)通信技術(shù),非常適合那些只需要從服務(wù)器向客戶(hù)端發(fā)送數(shù)據(jù)的應(yīng)用場(chǎng)景。
到此這篇關(guān)于Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Go SSE消息推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于golang?struct?中的?slice?無(wú)法原子賦值的問(wèn)題
這篇文章主要介紹了為什么?golang?struct?中的?slice?無(wú)法原子賦值的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01
Golang WaitGroup實(shí)現(xiàn)原理解析
WaitGroup是Golang并發(fā)的兩種方式之一,一個(gè)是Channel,另一個(gè)是WaitGroup,下面這篇文章主要給大家介紹了關(guān)于golang基礎(chǔ)之waitgroup用法以及使用要點(diǎn)的相關(guān)資料,需要的朋友可以參考下2023-02-02
一文帶你使用golang手?jǐn)]一個(gè)websocket中間件
這篇文章主要為大家詳細(xì)介紹了如何使用golang手?jǐn)]一個(gè)websocket中間件,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以參考一下2023-12-12
GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟
我們開(kāi)發(fā)項(xiàng)目常常將項(xiàng)目上傳到linux遠(yuǎn)程服務(wù)器上來(lái)運(yùn)行,本文主要介紹了GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Golang實(shí)現(xiàn)根據(jù)某個(gè)特定字段對(duì)結(jié)構(gòu)體的順序進(jìn)行排序
這篇文章主要為大家詳細(xì)介紹了Golang如何實(shí)現(xiàn)根據(jù)某個(gè)特定字段對(duì)結(jié)構(gòu)體的順序進(jìn)行排序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
Go語(yǔ)言實(shí)現(xiàn)聊天小工具的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Go語(yǔ)言實(shí)現(xiàn)聊天小工具,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Go中defer使用場(chǎng)景及注意事項(xiàng)
defer 會(huì)在當(dāng)前函數(shù)返回前執(zhí)行傳入的函數(shù),它會(huì)經(jīng)常被用于關(guān)閉文件描述符、關(guān)閉數(shù)據(jù)庫(kù)連接以及解鎖資源。這篇文章主要介紹了Go中defer使用注意事項(xiàng),需要的朋友可以參考下2021-12-12
Golang語(yǔ)言的跨平臺(tái)UI工具包fyne使用詳解
這篇文章主要為大家介紹了Golang語(yǔ)言的跨平臺(tái)UI工具包fyne使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12

