0
点赞
收藏
分享

微信扫一扫

2024年ERP管理系统职业技能大赛软件测试赛项-销售专员模块Bug清单

夕颜合欢落 04-10 14:00 阅读 3
ginssegolang

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

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

package main

import (
	"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.Method
		c.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 type
	c.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 client
	println("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 map
	defer 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 list
	notify := c.Writer.CloseNotify()
	go func() {
		<-notify
		fmt.Println("Client disconnected")
	}()
	// Continuously send data to the client
	for {
		data := <-eventChan
		println("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 console
	println("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 to
	router.GET("/sse/:id", connect)
	// Handle POST request
	router.GET("/send/:id", sendMsg)
	// Start the server
	err := 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 server
        eventSource.onmessage = function (event) {
            const data = event.data;
            appendDataToDiv(data);
        };

        // Event listener for SSE errors
        eventSource.onerror = function (event) {
            console.error("SSE Error:", event);
        };

        // Function to append data to the SSE data div
        function 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号房间的所有用户

举报

相关推荐

0 条评论