当前位置: 首页 > news >正文

gin+sse实现离散的消息通知

虽然网上的都是用sse实现将实时消息流不间断的推给前端,但是sse也可以模拟websocket进行突发的消息通知,而不是一直读取数据并返回数据。即服务端保存所有的连接对象,前端管理界面发送正常的http请求,在后端遍历所有的连接对象,将消息广播。就可以实现一种类似双向通讯的形式了。

代码参考了Server-side Events (SSE) : A deep dive into client-server architecture | Implementation in Golang,在这基础上实现了房间机制,房间ID由前端生成并传递,鉴权机制请自行通过token+中间件等形式实现。

package mainimport ("fmt""net/http""github.com/gin-gonic/gin"
)// 房间号为key,client数组为value
var clients = make(map[string][]chan string)// 广播房间内的所有用户
func broadcast(roomID string, data string) {for _, client := range clients[roomID] {client <- data}
}
//配置跨域
func configCors() gin.HandlerFunc {return func(c *gin.Context) {method := c.Request.Methodc.Header("Access-Control-Allow-Origin", "*")c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")c.Header("Access-Control-Allow-Headers", "*")c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")c.Header("Access-Control-Allow-Credentials", "true")//放行所有OPTIONS方法if method == "OPTIONS" {c.AbortWithStatus(http.StatusNoContent)}// 处理请求c.Next()}
}//前端初始化时连接该接口
func connect(c *gin.Context) {roomID := c.Param("id")// Set the response header to indicate SSE content typec.Header("Content-Type", "text/event-stream")c.Header("Cache-Control", "no-cache")c.Header("Connection", "keep-alive")// Create a channel to send events to the clientprintln("Client connected")eventChan := make(chan string)if clients[roomID] == nil {clients[roomID] = []chan string{}}clients[roomID] = append(clients[roomID], eventChan) // Add the client to the clients mapdefer func() {// 删除该房间的该用户,按值删除数组元素for _, v := range clients[roomID] {if v != eventChan {clients[roomID] = append(clients[roomID], v)}}close(eventChan)}()// Listen for client close and remove the client from the listnotify := c.Writer.CloseNotify()go func() {<-notifyfmt.Println("Client disconnected")}()// Continuously send data to the clientfor {data := <-eventChanprintln("Sending data to client", data)fmt.Fprintf(c.Writer, "data: %s\n\n", data)c.Writer.Flush()}
}// 发送消息接口
func sendMsg(c *gin.Context) {// data := c.PostForm("data")roomID := c.Param("id")data := c.DefaultQuery("name", "urlyy")// print data to consoleprintln("Data received from client :", data)broadcast(roomID, data)c.JSON(http.StatusOK, gin.H{"message": "Data sent to clients"})
}func main() {router := gin.Default()router.Use(configCors())// SSE endpoint that the clients will be listening torouter.GET("/sse/:id", connect)// Handle POST requestrouter.GET("/send/:id", sendMsg)// Start the servererr := router.Run(":6666")if err != nil {fmt.Println(err)}
}

前端代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>SSE Client</title>
</head><body><h1>SSE Client</h1><div id="sse-data"></div><script>const sseDataElement = document.getElementById("sse-data");// Create an EventSource to listen to the /sse endpoint// 注意这里多加了一个路径属性,就是房间ID// 测试时可以另建一个html文件,将它的房间ID更改成不一样的const eventSource = new EventSource("http://localhost:6666/sse/1");// Event listener for messages received from the servereventSource.onmessage = function (event) {const data = event.data;appendDataToDiv(data);};// Event listener for SSE errorseventSource.onerror = function (event) {console.error("SSE Error:", event);};// Function to append data to the SSE data divfunction appendDataToDiv(data) {const p = document.createElement("p");p.textContent = data;sseDataElement.appendChild(p);}</script>
</body></html>

发送消息的接口
http://127.0.0.1:8587/send/1?name=1234,name不传则默认为urlyy。调用该接口会将消息1234发给1号房间的所有用户

http://www.lryc.cn/news/336421.html

相关文章:

  • C++ //练习 11.38 用unordered_map重写单词计数程序(参见11.1节,第375页)和单词转换程序(参见11.3.6节,第391页)。
  • 【示例】MySQL-4类SQL语言-DDL-DML-DQL-DCL
  • 基于SpringBoot+Vue的果蔬种植销售一体化服务平台(源码+文档+部署+讲解)
  • 数据结构面试
  • Linux 上安装 SQLite
  • C++模板初阶(个人笔记)
  • 如何用Java后端处理JS.XHR请求
  • 分布式锁-redission
  • C/C++ 自定义头文件,及头文件结构详解
  • 快速列表quicklist
  • 《MATLAB科研绘图与学术图表绘制从入门到精通》
  • Day3-struct类型、列转行、行转列、函数
  • C++设计模式:构建器模式(九)
  • OJ 【难度1】【Python】完美字符串 扫雷 A-B数对 赛前准备 【C】精密计时
  • 【Tars-go】腾讯微服务框架学习使用01--初始化服务
  • 通过pre标签进行json格式化展示,并实现搜索高亮和通过鼠标进行逐个定位的功能
  • 5分钟了解清楚【osgb】格式的倾斜摄影数据metadata.xml有几种规范
  • CCIE-10-IPv6-TS
  • 《QT实用小工具·十七》密钥生成工具
  • CSP 比赛经验分享
  • 探究“大模型+机器人”的现状和未来
  • Commitizen:规范化你的 Git 提交信息
  • 官网下载IDE插件并导入IDE
  • 三行命令解决Ubuntu Linux联网问题
  • AI大模型在自然语言处理中的应用:性能表现和未来趋势
  • 三防平板定制服务:亿道信息与个性化生产的紧密结合
  • 【备战蓝桥杯】2024蓝桥杯赛前突击省一:基础数论篇
  • golang es查询的一些操作,has_child,inner_hit,对索引内父子文档的更新
  • 精准备份:如何自动化单个MySQL数据库的备份过程
  • Green Hills 自带的MULTI调试器查看R7芯片寄存器