ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

使用 gin-contrib/sse 在 Gin 中实现 Server-Sent Events 实时推送

使用 gin-contrib/sse 在 Gin 中实现 Server-Sent Events 实时推送 后端示例工程【免费下载链接】go-gin-exampleAn example of gin项目地址https://gitcode.com/gh_mirrors/go/go-gin-example点击查看免费下载导读本文以 gin-contrib/sse 的官方 README 为核心系统讲解 Server-Sent EventsSSE技术及其在 Go/Gin 生态中的落地方式。SSE 允许浏览器通过一条普通的 HTTP 长连接持续接收来自服务器的自动更新是构建实时通知、日志流、消息推送等场景的轻量级方案。读完本文你将掌握sse.Event的字段语义与编码规则、text/event-stream内容类型的处理以及如何结合 Gin 框架的SSEvent方法快速向客户端推送事件并了解服务端对 SSE 流的解码支持。什么是 Server-Sent EventsServer-Sent EventsSSE是一种基于 HTTP 的技术浏览器通过一个 HTTP 连接从服务器持续接收自动更新。与 WebSocket 的双向全双工通信不同SSE 是服务器到浏览器的单向推送其客户端 APIEventSource已被 W3C 作为 HTML5 标准的一部分予以标准化。浏览器端的EventSource接口负责建立连接、自动重连并解析服务器下发的文本流开发者无需自己处理连接状态机。SSE 的典型应用场景包括实时消息/通知推送如站内信、告警日志流实时输出如构建过程、任务执行进度数据仪表盘定时刷新如监控指标、行情行情任何服务器主动、客户端被动接收的单向实时数据场景。在 Go 生态中gin-contrib/sse提供了 SSE 的编码Encode与解码Decode实现并被 gin-gonic/gin 框架直接依赖见 gin 的 go.mod是 Gin 应用实现 SSE 推送的标准组件。快速开始使用 sse.Encode 发送事件sse.Encode是核心的编码入口它接收一个io.Writer与一个sse.Event将事件按 SSE 规范写入流中。在原生net/http处理器中即可直接使用import github.com/gin-contrib/sse func httpHandler(w http.ResponseWriter, req *http.Request) { // data 可以是基本类型字符串、整数或浮点数 sse.Encode(w, sse.Event{ Event: message, Data: some data\nmore data, }) // 也可以是复杂类型map、struct 或 slice sse.Encode(w, sse.Event{ Id: 124, Event: message, Data: map[string]interface{}{ user: manu, date: time.Now().Unix(), content: hi!, }, }) }上述代码产生的网络流如下event: message data: some data\\nmore data id: 124 event: message data: {content:hi!,date:1431540810,user:manu}注意两点第一段Data中的换行符\n被转义为字面量\\n即\n两个字符保证单行data:字段不会被截断第二段传入的是map[string]interface{}编码器自动将其序列化为 JSON 字符串。Event 结构体字段解析从 sse-encoder.go 可以看到Event的定义type Event struct { Event string Id string Retry uint Data interface{} }字段类型对应 SSE 协议字段说明Eventstringevent:事件类型名客户端可用addEventListener(类型名)订阅为空时客户端默认触发message事件Idstringid:事件 ID用于断线重连时客户端携带Last-Event-ID向服务器续传Retryuintretry:客户端断线后的重连时间毫秒为 0 时不输出该字段Datainterface{}data:事件数据支持任意 Go 类型Encode的写入顺序固定为id→event→retry→data见 Encode 函数其中只有非空字段才会真正输出对应行writeId 对空id直接跳过writeRetry 对retry 0直接跳过。基本类型与复杂类型的编码差异writeData 揭示了Data的编码策略——通过反射判断数据类型结构体Struct、切片Slice、映射Map调用json.NewEncoder(w).Encode(data)序列化为 JSON 后输出末尾额外追加一个换行其余基本类型字符串、整数、浮点数、布尔等通过fmt.Sprint转为字符串后原样输出并追加\n\n表示事件结束。其中kindOfDatasse-encoder.go会先解引用指针reflect.Ptr时取Elem().Kind()因此传入结构体指针同样会被当作复杂类型处理。这意味著你完全可以传入自定义结构体客户端将收到其 JSON 序列化结果——但注意Data是interface{}序列化 JSON 时字段名遵循 Go 的 JSON 标签规则。多行数据与字段转义SSE 协议规定data:字段不能包含裸换行。编码器通过两个strings.Replacer解决这一问题sse-encoder.govar fieldReplacer strings.NewReplacer( \n, \\n, \r, \\r) var dataReplacer strings.NewReplacer( \n, \ndata:, \r, \\r)fieldReplacer用于id:、event:、retry:等字段名行其中的换行与回车被转义为字面量\\n、\\r防止破坏行结构dataReplacer用于data:数据行换行被转换为\ndata:即把多行数据拆分为多个连续的data:行这正是 README 示例中some data\nmore data输出为两行data:的底层原因回车则转义为\\r。因此当Data是字符串且包含换行时客户端收到的将是多条data:行EventSource会自动用\n拼接成完整数据。Content-Typetext/event-streamSSE 响应必须携带专用 MIME 类型否则浏览器端的EventSource会拒绝解析。该常量定义于 sse-encoder.goconst ContentType text/event-stream可以通过以下代码直接打印验证fmt.Println(sse.ContentType)输出text/event-stream当Event作为 Gin 的 Render 渲染器使用时见下文其 WriteContentType 方法会同时设置两个响应头Content-Type: text/event-streamCache-Control: no-cache仅当开发者未显式设置时补充Cache-Control已存在则保留原值no-cache用于阻止代理服务器和浏览器缓存 SSE 响应流保证推送的实时性。与 Gin 框架集成SSEvent 方法sse.Event实现了 Gin 渲染器所需的Render接口——Render(http.ResponseWriter)与WriteContentType(http.ResponseWriter)见 sse-encoder.go。因此 Gin 在 context.go 中提供了开箱即用的封装// SSEvent writes a Server-Sent Event into the body stream. func (c *Context) SSEvent(name string, message interface{}) { c.Render(-1, sse.Event{ Event: name, Data: message, }) }在 Gin 路由处理器中实现 SSE 推送的典型写法func streamHandler(c *gin.Context) { w : c.Writer // 关键设置 SSE 必需的响应头 w.Header().Set(Content-Type, text/event-stream) w.Header().Set(Cache-Control, no-cache) w.Header().Set(Connection, keep-alive) // 循环推送事件 for i : 0; ; i { c.SSEvent(message, map[string]interface{}{ index: i, time: time.Now().Unix(), }) w.Flush() // 立即将缓冲数据刷给客户端 time.Sleep(1 * time.Second) } }配合 Gin 的 Stream 方法基于CloseNotify检测客户端是否断开即可构建完整的推送循环。需要注意本仓库 go-gin-example 本身并未在业务路由中启用 SSE上述集成代码是基于 Gin 对sse模块的官方依赖关系给出的标准用法。解码支持解析服务端 SSE 流除编码外gin-contrib/sse还提供了客户端侧的解码能力。README 中说明客户端实现即将推出coming soon而在当前 vendored 版本中已具备完整的解码实现sse-decoder.go。解码入口为func Decode(r io.Reader) ([]Event, error)Decode将流按\n切分为行严格按 W3C 规范处理空行触发当前事件的派发并重置事件与数据缓冲区decode:开头的行视为注释直接忽略sse-decoder.go无冒号的行整行作为字段名值为空字符串sse-decoder.go含冒号的行冒号前为字段名冒号后为字段值且值开头的单个空格会被去除sse-decoder.go字段分发event设置事件名id设置事件 IDdata追加到数据缓冲区每行后自动补\n未知字段直接忽略sse-decoder.go流末尾最后再派发一次未完成的事件sse-decoder.go。在派发时dispatchEvent解码器会去掉数据缓冲区末尾的\n并为未指定event名称的事件自动补上默认值message与浏览器EventSource的行为保持一致。这意味着你可以用同一套Event类型在服务端解析来自其他 SSE 源的流数据实现 SSE 网关或代理。使用前提与限制版本要求当前 vendored 版本模块声明为module github.com/gin-contrib/sse要求go 1.12及以上见 sse 的 go.mod并以 MIT 许可证发布单向通信SSE 仅支持服务器 → 客户端推送客户端向服务器发送数据仍需走普通 HTTP 请求连接数限制每个浏览器对同一域名HTTP/1.1的并发连接数有限大规模推送场景需考虑连接复用或 HTTP/2浏览器支持EventSource为 HTML5 标准 API现代主流浏览器均已支持在不支持的浏览器中需提供降级方案如轮询。综上gin-contrib/sse用不到两百行源码实现了对 SSE 协议编码与解码的完整覆盖配合 Gin 的SSEvent封装是在 Go 应用中快速落地服务器实时推送的高性价比选择。读者可进一步阅读 sse-encoder.go 与 sse-decoder.go 的完整实现理解每一个协议细节。赞分享后端示例工程【免费下载链接】go-gin-exampleAn example of gin项目地址https://gitcode.com/gh_mirrors/go/go-gin-example点击查看免费下载相关推荐在 Nhost 中用 gin-contrib/sse 构建 Server-Sent Events 流式推送在 Nhost 中用 gin contrib/sse 构建 Server Sent Events 流式推送 导读 Server Sent EventsSSE后端认证鉴权数据库无服务开发工具云原生OpenCloud 中的 SSE 实时推送基于 r3labs/sse 的 Server-Sent Events 实战指南OpenCloud 中的 SSE 实时推送基于 r3labs/sse 的 Server Sent Events 实战指南 导读 Server Sent Eve后端微服务存储认证鉴权DLSS Swapper:5分钟换好DLSS版本DLSS Swapper:5分钟换好DLSS版本 游戏内置的DLSS太旧,或者新更新之后画面出了问题?DLSS Swapper让你在 不更新游戏 的前提下,直接桌面应用上一篇SD-WebUI-Inpaint-Anything自定义修复模型完全指南3步解决模型不显示问题下一篇KKManager终极指南如何轻松管理Illusion游戏的Mod、插件和角色卡创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表