[Go实战]:SSE消息推送

前言

在现代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 mainimport ("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():returndefault: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作为一种轻量级的实时通信技术,非常适合那些只需要从服务器向客户端发送数据的应用场景。希望本文能对你有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/18855.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

使用OkHttp进行HTTPS请求的Kotlin实现

OkHttp简介 OkHttp是一个高效的HTTP客户端&#xff0c;它支持同步和异步请求&#xff0c;自动处理重试和失败&#xff0c;支持HTTPS&#xff0c;并且可以轻松地与Kotlin协程集成。OkHttp的设计目标是提供最简洁的API&#xff0c;同时保持高性能和低延迟。 为什么选择OkHttp …

【技术解析】Dolphinscheduler实现MapReduce任务的高效管理

MapReduce是一种编程模型&#xff0c;用于处理和生成大数据集&#xff0c;主要用于大规模数据集&#xff08;TB级数据规模&#xff09;的并行运算。本文详细介绍了Dolphinscheduler在MapReduce任务中的应用&#xff0c;包括GenericOptionsParser与args的区别、hadoop jar命令参…

Linux :进程间通信之管道

一、进程间通信 1.1 是什么和为什么 1、进程间通信是什么&#xff1f;&#xff1f; ——>两个或多个进程实现数据层面的交互&#xff0c;但是由于进程独立性的存在&#xff0c;导致通信的成本比较高。 2、既然通信成本高&#xff0c;那为什么还要通信呢&#xff1f;&…

Vue基础(2)_el和data的两种写法

举例&#xff1a; <div id"root"><h1>你好&#xff0c;{{name}}</h1> </div> el和data的2种写法 1.el有2种写法 (1).new Vue时候配置el属性。 // 第一种写法&#xff1a;new Vue时候配置el属性。// 优点&#xff1a;简单、直接new Vue({e…

【汇编语言】数据处理的两个基本问题(二) —— 解密汇编语言:数据长度与寻址方式的综合应用

文章目录 前言1. 指令要处理的数据有多长&#xff1f;1.1 通过寄存器指明数据的尺寸1.1.1 字操作1.1.2 字节操作 1.2 用操作符X ptr指明内存单元的长度1.2.1 访问字单元1.2.2 访问字节单元1.2.3 为什么要用操作符X ptr指明 1.3 其他方法 2. 寻址方式的综合应用2.1 问题背景&…

c++多态(深度刨析)

C系列-----多态 文章目录 C系列-----多态前言一、多态的概念二、多态的定义及实现2.1、多态构成的条件2.1.1、虚函数2.1.2、虚函数的重写 2.2、C11 override 和 final2.3、重载、覆盖(重写)、隐藏(重定义)的对比2.4、抽象类2.5、 接口继承和实现继承 三、多态的原理3.1、虚函数…

FPGA开发技能(9)快速生成约束XDC文件

文章目录 1.从Cadence导出csv约束文件2.python程序将csv导出为xdc文件。3.python生成exe4.exe使用注意事项5.传送门 前言&#xff1a; 作为一名FPGA工程师&#xff0c;通常公司会对该岗位的人有一定的硬件能力的要求&#xff0c;最基础的就是需要依据原理图的设计进行FPGA工程内…

css uniapp背景图宽度固定高度自适应可以重复

page {height: 100%;background-image: url(https://onlinekc.a.hlidc.cn/uploads/20241115/350f94aaf493d05625a7ddbc86c7804e.png);background-repeat: repeat;background-size: contain;} 如果不要重复 把background-repeat: repeat;替换background-repeat: no-repeat;

Stable Diffusion核心网络结构——U-Net

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

学习threejs,使用AnimationMixer实现变形动画

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AnimationMixer 动画…

【Linux】指令 + 重定向操作

Linux基本指令 一.Linux基本指令1.mv&#xff08;重要&#xff09;2.cat3.more和less&#xff08;重要&#xff09;4.head和tail5.date6.cal7.find&#xff08;重要&#xff09; 二.Linux相关知识点1. Linux系统中&#xff1a;一切皆文件2. 重定向操作1. 输出重定向2. 追加重定…

SpringBoot源码解析(四):解析应用参数args

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext SpringBoot源码解析(三)&#xff1a;启动开始阶段 SpringBoot源码解析(四)&#xff1a;解析应用参数args 目录…

Vue3.0 + Ts:动态设置style样式 ts 报错

error TS2322: Type ‘{ width: string; left: string; ‘background-color’: unknown; ‘z-index’: number; }’ is not assignable to type ‘StyleValue’ 在 vue3.0 ts 项目中&#xff0c;动态设置样式报错 在 Vue 3 TypeScript 项目中&#xff0c;当你使用 :style 绑…

跨平台WPF框架Avalonia教程 十六

SelectableTextBlock 可选文本块 SelectableTextBlock 块是一个用于显示文本的标签&#xff0c;允许选择和复制文本。它可以显示多行&#xff0c;并且可以完全控制所使用的字体。 有用的属性​ 您可能最常使用这些属性&#xff1a; 属性描述SelectionStart当前选择的起始字…

【MySQL】库的基础操作入门指南

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL入门指南&#xff1a;从零开始的数据库之旅 欢迎大家点赞收藏评论&#x1f60a; 目录 ☁创建数据库语法说明&#xff1a; 创建数据库案例 &#x1f308;字符集和校验规则查看系统默认字符集…

数据仓库数据湖湖仓一体解决方案

一、资料介绍 数据仓库与数据湖是现代数据管理的两大核心概念。数据仓库是结构化的数据存储仓库&#xff0c;用于支持企业的决策分析&#xff0c;其数据经过清洗、整合&#xff0c;以固定的模式存储&#xff0c;适合复杂查询。数据湖则是一个集中存储大量原始数据的存储库&…

人工智能英伟达越来越“大”的GPU

英伟达&#xff1a;让我们遇见越来越“大”的GPU 在2024年台北ComputeX大会上&#xff0c;英伟达CEO黄仁勋发表了题为《揭开新工业革命序幕》的演讲。他手持一款游戏显卡(很有可能是4090),自豪地宣称&#xff1a;“这是目前最先进的游戏GPU。”紧接着&#xff0c;他走到一台DGX…

知识库搭建:高科技行业的智慧基石与未来展望

一、引言 在科技日新月异的今天&#xff0c;知识密集型作业已成为高科技企业竞争力的核心。面对快速的技术迭代和激烈的市场竞争&#xff0c;如何高效地管理和运用知识资源&#xff0c;成为高科技企业必须面对的挑战。知识库&#xff0c;作为知识管理的核心平台&#xff0c;正…

算法编程题-删除子文件夹

算法编程题-删除子文件夹 原题描述设计思路代码实现复杂度分析 前一段时间面试字节的时候&#xff0c;被问到gin框架的路由结构。gin框架的路由结构采用的一般是前缀树来实现&#xff0c;于是被要求手写前缀树来实现路由的注册和查找。 本文以 leetcode 1233为例介绍一下前缀树…

利用SSH中的弱私钥

import paramiko import argparse import os from threading import Thread, BoundedSemaphore # 设置最大连接数 maxConnections 5 # 创建一个有界信号量&#xff0c;用于控制同时进行的连接数 connection_lock BoundedSemaphore(valuemaxConnections) # 用于控制是否停止所…