Go实现SSE消息推送的项目实战

 更新时间:2025年05月25日 09:21:51   作者:寻找09之夏  
本文主要介绍了Go实现SSE消息推送的项目实战,结合JavaScript前端集成,构建实时数据推送系统,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧

前言

在现代Web开发中,前后端分离已成为主流趋势。为了实现实时数据推送,Server-Sent Events (SSE) 是一种高效且易于实现的技术。本文将介绍如何在Go语言中实现SSE服务端,并在前端使用JavaScript进行集成,实现一个完整的实时数据推送系统

1. SSE简介

Server-Sent Events (SSE) 是HTML5的一项技术,用于服务器向浏览器自动发送更新信息。SSE的主要特点包括:

  • 单向通信:数据流是从服务器到客户端的单向流动。
  • 自动重连:如果连接断开,客户端会自动尝试重新建立连接。
  • 简单易用:相比WebSocket,SSE的API更简单,更容易上手。
  • 文本格式:SSE的数据是以文本形式发送的,通常为JSON或纯文本。

2. 后端实现

2.1 设置静态文件目录

首先,我们需要设置静态文件目录,以便前端页面和其他静态资源可以被正确加载。

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"
)

func main() {
	// 设置静态文件目录
	fs := http.FileServer(http.Dir("./static"))
	http.Handle("/", fs)

	// 设置 SSE 处理器
	http.HandleFunc("/events", handleEvents)

	// 启动服务器
	http.ListenAndServe(":8080", nil)
}

2.2 设置SSE处理器

接下来,我们创建一个SSE处理器来处理客户端的SSE请求,并设置正确的响应头。

func handleEvents(w http.ResponseWriter, r *http.Request) {
	// 设置 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")

	// 设置响应头
	w.Header().Set("Content-Type", "text/event-stream")
	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Connection", "keep-alive")

	// 模拟数据流
	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 {
			// 客户端断开连接,输出日志
			fmt.Println("Client disconnected:", err)
			return
		}

		// 刷新缓冲区
		if flusher, ok := w.(http.Flusher); ok {
			flusher.Flush()
		}

		// 检查是否应该关闭连接
		select {
		case <-r.Context().Done():
			return
		default:
			time.Sleep(2 * time.Second) // 每2秒发送一次消息
		}
	}
}

2.3 启动HTTP服务器

在上面的代码中,我们定义了两个路由:

  • /:处理静态文件请求。
  • /events:处理SSE请求。

3. 前端实现

3.1 创建前端页面

创建一个名为 index.html 的文件,用于展示接收到的消息。将该文件放在 main.go 同级地 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>服务器发送事件示例</h1>
    <div id="messages"></div>
    <div id="clock"></div>
</div>

<script>
    // 创建一个新的 EventSource 实例
    const eventSource = new EventSource('/events');

    // 监听消息事件
    eventSource.onmessage = function (event) {
        const newMessage = document.createElement('p');
        newMessage.textContent = 'New message: ' + event.data;
        document.getElementById('messages').appendChild(newMessage);

        // 滚动到底部
        const messagesDiv = document.getElementById('messages');
        messagesDiv.scrollTop = messagesDiv.scrollHeight;
    };

    // 监听错误事件
    eventSource.onerror = function (error) {
        console.error('EventSource failed:', error);
        eventSource.close();
    };
</script>
</body>
</html>
  • 创建EventSource对象:const eventSource = new EventSource('/events'); 创建一个EventSource对象,连接到服务器的 /events 路由。
  • 处理消息:eventSource.onmessage 事件处理器用于处理从服务器接收到的消息,并将其显示在页面上。
  • 处理错误:eventSource.onerror 事件处理器用于处理连接错误,并在发生错误时关闭连接。
  • 自动滚动:每次接收到新消息时,自动滚动到消息列表的底部,确保用户始终能看到最新的消息。

4. 运行项目

4.1 启动服务:

go run main.go

打开浏览器,访问 http://localhost:8080,你应该能看到每两秒钟从服务器推送的一条新消息,且页面内容全屏自适应,样式更加美观。

5 注意事项

5.1 客户端连接限制

  • 浏览器对每个域名下的SSE连接数有限制。大多数现代浏览器允许每个域名最多6个并发连接。如果超过这个限制,新的连接将会被阻塞,直到有连接关闭。
  • 如果你的应用需要支持更多的并发连接,可以考虑使用子域名或负载均衡来分散连接。

5.2 服务器资源管理

  • 每个SSE连接都会占用服务器的一个goroutine,因此需要合理管理服务器资源。如果预期会有大量并发连接,建议使用连接池或其他资源管理机制。
  • 可以通过设置超时、心跳检测等方式来管理长时间未活动的连接,避免资源浪费。

5.3 错误处理和重连

  • 客户端可以通过 onerror 事件处理器来处理连接错误,并实现自动重连逻辑。
  • 服务器端可以在连接关闭时发送适当的错误信息,帮助客户端更好地处理异常情况。

5.4 安全性

  • 确保SSE接口的安全性,避免暴露敏感数据。可以使用HTTPS来加密传输数据。
  • 对于需要认证的场景,可以在SSE请求中携带认证信息,例如使用HTTP头部或Cookie。

总结

本文详细介绍了如何在Go语言中实现SSE(Server-Sent Events)服务端,并在前端使用JavaScript进行集成,实现一个完整的实时数据推送系统。SSE作为一种轻量级的实时通信技术,非常适合那些只需要从服务器向客户端发送数据的应用场景。

到此这篇关于Go实现SSE消息推送的项目实战的文章就介绍到这了,更多相关Go SSE消息推送内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang学习之map的用法详解

    Golang学习之map的用法详解

    在Golang(又称Go语言)中,map是一种非常有用的数据结构,所以这篇文章小编就来带大家一起深入了解一下map的用法,感兴趣的小伙伴可以了解一下
    2023-06-06
  • 关于golang struct 中的 slice 无法原子赋值的问题

    关于golang struct 中的 slice 无法原子赋值的问题

    这篇文章主要介绍了为什么 golang struct 中的 slice 无法原子赋值的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-01-01
  • Golang WaitGroup实现原理解析

    Golang WaitGroup实现原理解析

    WaitGroup是Golang并发的两种方式之一,一个是Channel,另一个是WaitGroup,下面这篇文章主要给大家介绍了关于golang基础之waitgroup用法以及使用要点的相关资料,需要的朋友可以参考下
    2023-02-02
  • 一文带你使用golang手撸一个websocket中间件

    一文带你使用golang手撸一个websocket中间件

    这篇文章主要为大家详细介绍了如何使用golang手撸一个websocket中间件,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以参考一下
    2023-12-12
  • GoLand一键上传项目到远程服务器的方法步骤

    GoLand一键上传项目到远程服务器的方法步骤

    我们开发项目常常将项目上传到linux远程服务器上来运行,本文主要介绍了GoLand一键上传项目到远程服务器的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Golang实现根据某个特定字段对结构体的顺序进行排序

    Golang实现根据某个特定字段对结构体的顺序进行排序

    这篇文章主要为大家详细介绍了Golang如何实现根据某个特定字段对结构体的顺序进行排序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • Go语言实现聊天小工具的示例代码

    Go语言实现聊天小工具的示例代码

    这篇文章主要为大家详细介绍了如何利用Go语言实现聊天小工具,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Go语言中interface语法与使用详解

    Go语言中interface语法与使用详解

    Go语言里面设计最精妙的应该算interface,它让面向对象,内容组织实现非常的方便,下面这篇文章主要给大家介绍了关于Go语言中interface语法与使用的相关资料,需要的朋友可以参考下
    2022-07-07
  • Go中defer使用场景及注意事项

    Go中defer使用场景及注意事项

    defer 会在当前函数返回前执行传入的函数,它会经常被用于关闭文件描述符、关闭数据库连接以及解锁资源。这篇文章主要介绍了Go中defer使用注意事项,需要的朋友可以参考下
    2021-12-12
  • Golang语言的跨平台UI工具包fyne使用详解

    Golang语言的跨平台UI工具包fyne使用详解

    这篇文章主要为大家介绍了Golang语言的跨平台UI工具包fyne使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12

最新评论