当前位置: 首页 > 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号房间的所有用户

相关文章:

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

虽然网上的都是用sse实现将实时消息流不间断的推给前端&#xff0c;但是sse也可以模拟websocket进行突发的消息通知&#xff0c;而不是一直读取数据并返回数据。即服务端保存所有的连接对象&#xff0c;前端管理界面发送正常的http请求&#xff0c;在后端遍历所有的连接对象&am…...

C++ //练习 11.38 用unordered_map重写单词计数程序(参见11.1节,第375页)和单词转换程序(参见11.3.6节,第391页)。

C Primer&#xff08;第5版&#xff09; 练习 11.38 练习 11.38 用unordered_map重写单词计数程序&#xff08;参见11.1节&#xff0c;第375页&#xff09;和单词转换程序&#xff08;参见11.3.6节&#xff0c;第391页&#xff09;。 环境&#xff1a;Linux Ubuntu&#xff0…...

【示例】MySQL-4类SQL语言-DDL-DML-DQL-DCL

前言 本文主要讲述MySQL中4中SQL语言的使用及各自特点。 SQL语言总共分四类&#xff1a;DDL、DML、DQL、DCL。 SQL-DDL | Data Definition Language 数据定义语言&#xff1a;用来定义/更改数据库对象&#xff08;数据库、表、字段&#xff09; 用途 | 操作数据库 # 查询所…...

基于SpringBoot+Vue的果蔬种植销售一体化服务平台(源码+文档+部署+讲解)

一.系统概述 伴随着我国社会的发展&#xff0c;人民生活质量日益提高。于是对果蔬种植销售一体化服务管理进行规范而严格是十分有必要的&#xff0c;所以许许多多的信息管理系统应运而生。此时单靠人力应对这些事务就显得有些力不从心了。所以本论文将设计一套果蔬种植销售一体…...

数据结构面试

当然可以&#xff01;以下是数据结构面试问题及答案整理&#xff1a; **什么是数据结构&#xff1f;** 答&#xff1a;数据结构是指组织和存储数据的方式&#xff0c;它允许高效地访问和操作数据。不同的数据结构有不同的优势和适用场景。常见的基本数据结构包括数组、链表、…...

Linux 上安装 SQLite

SQLite Download Page 从上面的链接中源代码区下载 sqlite-autoconf-*.tar.gz。 历史版本见下连接&#xff1a; https://sqlite.org/chronology.html...

C++模板初阶(个人笔记)

模板初阶 1.泛型编程2.函数模板2.1函数模板的实例化2.2模板参数的匹配规则 3.类模板3.1类模板的实例化 1.泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 //函数重载 //交换函数的逻辑是一致的&#xff0c…...

如何用Java后端处理JS.XHR请求

Touching searching engine destroies dream to utilize php in tomcat vector.The brave isn’t knocked down&#xff0c;turn its path to java back-end. Java Servlet Bible schematic of interaction between JS front-end and Java back-end Question 如何利用Java…...

分布式锁-redission

5、分布式锁-redission 5.1 分布式锁-redission功能介绍 基于setnx实现的分布式锁存在下面的问题&#xff1a; 重入问题&#xff1a;重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中&#xff0c;可重入锁的意义在于防止死锁&#xff0c;比如HashTable这样的代码…...

C/C++ 自定义头文件,及头文件结构详解

头文件 在之前介绍的大部分C语言语法基础的章节中列举的实例代码部分&#xff0c;都会在源文件的开始的第一行通过#include预处理指令包含进"stdio.h"&#xff0c;后面这个".h"后缀名的就是头文件了。而什么是头文件呢&#xff1f; 通俗方式理解头文件 …...

快速列表quicklist

目录 为什么使用快速列表quicklist 对比双向链表 对比压缩列表ziplist quicklist结构 节点结构quicklistNode quicklist 管理ziplist信息的结构quicklistEntry 迭代器结构quicklistIter quicklist的API 1.创建快速列表 2.创建快速列表节点 3.头插quicklistPushHead …...

《MATLAB科研绘图与学术图表绘制从入门到精通》

解锁MATLAB科研绘图魅力&#xff0c;让数据可视化成为你的科研利器&#xff01; 1.零基础快速入门&#xff1a;软件操作实战案例图文、代码结合讲解&#xff0c;从入门到精通快速高效。 2.多种科研绘图方法&#xff1a;科研绘图基础变量图形极坐标图形3D图形地理信息可视化等&a…...

Day3-struct类型、列转行、行转列、函数

Hive 数据类型 struct类型 struct&#xff1a;结构体&#xff0c;对应了Java中的对象&#xff0c;实际上是将数据以json形式来进行存储和处理 案例 原始数据 a tom,19,male amy,18,female b bob,18,male john,18,male c lucy,19,female lily,19,female d henry,18,male davi…...

C++设计模式:构建器模式(九)

1、定义与动机 定义&#xff1a;将一个复杂对象的构建与其表示相分离&#xff0c;使得同样的构建过程&#xff08;稳定&#xff09;可以创建不同的表示&#xff08;变化&#xff09; 动机&#xff1a; 在软件系统中&#xff0c;有时候面临着“一个复杂对象”的创建工作&#x…...

OJ 【难度1】【Python】完美字符串 扫雷 A-B数对 赛前准备 【C】精密计时

完美字符串 题目描述 你可能见过下面这一句英文&#xff1a; "The quick brown fox jumps over the lazy dog." 短短的一句话就包含了所有 2626 个英文字母&#xff01;因此这句话广泛地用于字体效果的展示。更短的还有&#xff1a; "The five boxing wizards…...

【Tars-go】腾讯微服务框架学习使用01--初始化服务

1 初始INIT-Demo运行 按照官网描述 go get 安装框架依赖 # < go 1.16 go get -u github.com/TarsCloud/TarsGo/tars/tools/tarsgo go get -u github.com/TarsCloud/TarsGo/tars/tools/tars2go # > go 1.16 go install github.com/TarsCloud/TarsGo/tars/tools/tarsgolat…...

通过pre标签进行json格式化展示,并实现搜索高亮和通过鼠标进行逐个定位的功能

功能说明 实现一个对json进行格式化的功能添加搜索框&#xff0c;回车进行关键词搜索&#xff0c;并对关键词高亮显示搜索到的多个关键词&#xff0c;回车逐一匹配监听json框&#xff0c;如果发生了编辑&#xff0c;需要在退出时提示&#xff0c;在得到用户确认的情况下再退出…...

5分钟了解清楚【osgb】格式的倾斜摄影数据metadata.xml有几种规范

数据格式同样都是osgb&#xff0c;不同软件生产的&#xff0c;建模是参数不一样&#xff0c;还是有很大区别的。尤其在应用阶段。 本文从建模软件、数据组织结构、metadata.xml&#xff08;投影信息&#xff09;、应用几个方面进行了经验性总结。不论您是初步开始建模&#xf…...

CCIE-10-IPv6-TS

目录 实验条件网络拓朴 环境配置开始Troubleshooting问题1. R25和R22邻居关系没有建立问题2. 去往R25网络的下一跳地址不存在、不可用问题3. 去往目标网络的下一跳地址不存在、不可用 实验条件 网络拓朴 环境配置 在我的资源里可以下载&#xff08;就在这篇文章的开头也可以下…...

《QT实用小工具·十七》密钥生成工具

1、概述 源码放在文章末尾 该项目主要用于生成密钥&#xff0c;下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #pragma execution_character_set("utf-8")#include "frmmain.h" #include "ui_frmmain.h" #include "qmessag…...

CSP 比赛经验分享

中国软件专业技术资格&#xff08;水平&#xff09;考试&#xff08; CSP-S &#xff09;是一项旨在评价软件和信息技术 专业人员专业技术水平的考试。对于参加过 CSP 比赛的人来说&#xff0c;这是一个展示 自己编程能力、逻辑思维和解决问题能力的好机会。下面是一些基于…...

探究“大模型+机器人”的现状和未来

基础模型(Foundation Models)是近年来人工智能领域的重要突破&#xff0c;在自然语言处理和计算机视觉等领域取得了显著成果。将基础模型引入机器人学&#xff0c;有望从感知、决策和控制等方面提升机器人系统的性能&#xff0c;推动机器人学的发展。由斯坦福大学、普林斯顿大学…...

Commitizen:规范化你的 Git 提交信息

简介 在团队协作开发过程中&#xff0c;规范化的 Git 提交信息可以提高代码维护的效率&#xff0c;便于追踪和定位问题。Commitizen 是一个帮助我们规范化 Git 提交信息的工具&#xff0c;它提供了一种交互式的方式来生成符合约定格式的提交信息。 原理 Commitizen 的核心原…...

官网下载IDE插件并导入IDE

官网下载IDEA插件并导入IDEA 1. 下载插件2. 导入插件 1. 下载插件 地址&#xff1a;https://plugins.jetbrains.com/plugin/21068-codearts-snap/versions 说明&#xff1a;本次演示以IDEA软件为例 操作&#xff1a; 等待下载完成 2. 导入插件 点击File->setting->Pl…...

三行命令解决Ubuntu Linux联网问题

本博客中Ubuntu版本为23.10.1最新版本&#xff0c;后续发现了很多问题我无法解决&#xff0c;已经下载了另外一个版本22.04&#xff0c;此版本自带网络 一开始我找到官方文档描述可以通过命令行连接到 WiFi 网络&#xff1a;https://cn.linux-console.net/?p10334#google_vig…...

AI大模型在自然语言处理中的应用:性能表现和未来趋势

引言 A. AI大模型在自然语言处理中的应用背景简介 近年来&#xff0c;随着深度学习和人工智能技术的快速发展&#xff0c;越来越多的研究人员和企业开始关注应用于自然语言处理的AI大模型。这些模型采用了深层的神经网络结构&#xff0c;具有强大的学习和处理能力&#xff0c…...

三防平板定制服务:亿道信息与个性化生产的紧密结合

在当今数字化时代&#xff0c;个性化定制已经成为了市场的一大趋势&#xff0c;而三防平板定制服务作为其中的一部分&#xff0c;展现了数字化技术与个性化需求之间的紧密结合。这种服务是通过亿道信息所提供的技术支持&#xff0c;为用户提供了满足特定需求的定制化三防平板&a…...

【备战蓝桥杯】2024蓝桥杯赛前突击省一:基础数论篇

2024蓝桥杯赛前突击省一&#xff1a;基础算法模版篇 基础数论算法回顾 判断质数&#xff08;试除法&#xff09; 时间复杂度O&#xff08;sqrt(n)&#xff09; static int is_prime(int n){if(n<2) return 0;for (int i2;i<n/i;i){if(n%i0) return 0;}return 1; }质因…...

golang es查询的一些操作,has_child,inner_hit,对索引内父子文档的更新

1.因为业务需要查询父文档以及其下子文档&#xff0c;搞了很久才理清楚。 首先还是Inner_hits,inner_hits只能用在nested,has_child,has_parents查询里面 {"query": {"nested": {"path": "comments","query": {"match…...

精准备份:如何自动化单个MySQL数据库的备份过程

自动化备份对于维护数据库的完整性和安全性至关重要。本指南将向您展示如何使用Shell脚本来自动化MySQL数据库的备份过程。 备份脚本内容 首先&#xff0c;这是我们将使用的备份脚本&#xff1a; #!/bin/bash# 完成数据库的定时备份 # 备份路径 BACKUP/data/backup/db # 当前…...