GoNote第六章 GoFrame 接入SSE

news/2024/11/26 5:31:29/

GoNote第六章 GoFrame 接入SSE

什么是SSE(Server Sent Events)

引用维基百科:

Server-Sent Events (SSE) is a server push technology enabling a client to receive automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is standardized as part of HTML5[1] by the W3C.

在Web开发时,由于HTTP是无状态的协议,所以客户端浏览器必须首先向服务器发送请求才能接收新数据。所以如果要实现服务端向客户端发起通知,通常可以使用WebSocket或者客户端长轮询(Long-Poling)的方式。但是其实如果只是服务端向客户端推送单方向的数据流时,可以使用H5标准中的SSE,SSE使用户可以订阅服务器端的实时数据流。

SSE与WebSocket

Server Sent Events(SSE)和WebSocket都是Web技术中用于实现实时通信的协议。它们之间的一些差异如下:

  1. SSE与WebSocket之间的主要区别在于,SSE是基于HTTP协议进行的,而WebSocket是独立的协议。因此,SSE可以轻松地使用现有的HTTP基础设施进行部署,而WebSocket则需要单独的网络端口并在服务器上进行特殊的配置。
  2. 对于服务器推送数据到客户端,SSE使用常规的HTTP响应,其中包含了许多按照事件流格式格式化的消息。而WebSocket则使用专用的双向数据通道,更适合双向通信的场景。
  3. 在使用SSE时,服务器推送消息的速度相对较慢,并且不能自由控制消息的发送时间间隔。而WebSocket具有更高的性能和更灵活的控制机制,可以处理更复杂的应用程序需求。
  4. 由于SSE是基于HTTP协议实现的,因此可以借助浏览器的缓存机制,从而减少网络流量和服务器负担。而WebSocket则需要通过自己的协议处理缓存问题,在这方面较为繁琐。

综上所述,SSE和WebSocket都有自己的优势和劣势,适用于不同的应用场景。对于需要快速构建实时通信的简单场景,SSE是一种快速且易于部署的解决方案。而对于更复杂的应用程序需求,WebSocket则提供了更高效的数据传输和更灵活的控制机制。

goFrame 引入SSE

Golang有开源库eventsource直接支持了SSE,在这里我们直接使用这个库构建服务器:

导入插件

gopkg.in/antage/eventsource.v1

直接运行,直接访问接口,获取响应值就行,

可以循环读取redis中的信息,推送给前端

package mainimport ("context""fmt""net/http""time""github.com/gogf/gf/v2/os/gtime""github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp""github.com/gogf/gf/v2/os/gctx""gopkg.in/antage/eventsource.v1"
)func main() {ctx := gctx.New()StartSSE(ctx)
}func StartSSE(ctx context.Context) {s := g.Server()s.BindHandler("/sse", func(r *ghttp.Request) {es := eventsource.New(&eventsource.Settings{Timeout:        5 * time.Second,IdleTimeout:    1 * time.Minute,CloseOnTimeout: true,},func(request *http.Request) [][]byte {return [][]byte{[]byte("Content-Type: text/event-stream; charset=utf-8"),[]byte("Connection: keep-alive"),[]byte("X-Accel-Buffering: no"), // 防止 nginx 中间启用缓存,导致不能刷新到客户端[]byte("Cache-Control: no-cache,no-store"),[]byte("Access-Control-Allow-Origin: *"),[]byte("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept"),}},)defer es.Close()es.ServeHTTP(r.Response.Writer, r.Request)// 请求参数校验eventId := r.Get("eventId").String()event := r.Get("event").String()eventTime := r.Get("eventTime").Int64()if eventId == "" || event == "" || eventTime < 1 {es.SendEventMessage("请求事件异常", event, eventId)return}now := gtime.Now()t := gtime.NewFromTimeStamp(eventTime)if now.Timestamp() < eventTime || now.Sub(t) > 3*time.Minute {es.SendEventMessage("请求事件超时", event, eventId)return}// 循环执行时间 3 分钟to := time.After(3 * time.Minute)for {select {case <-to:fmt.Println("Timeout!")returndefault:es.SendEventMessage("data数据", event, eventId)// 每秒轮询一次time.Sleep(1 * time.Second)}}})s.port(8080)s.Run()
}

跳转Html页面

type HelloReq struct {g.Meta `path:"/hello" tags:"Hello" method:"get" summary:"You first hello api"`
}
type HelloRes struct {g.Meta `mime:"text/html" type:"string" example:"<html/>" `
}var (Hello = cHello{}
)type cHello struct{}func (c *cHello) Hello(ctx context.Context, req *common.HelloReq) (res *common.HelloRes, err error) {err = g.RequestFromCtx(ctx).Response.WriteTpl("/home/index.html")liberr.ErrIsNil(ctx, err)return
}

客户端HTML页面

客户端HTML页面在resource/template目录下,通过new EventSource("/events")创建了前端的SSE接收实例对象evsrc,并设置了onmessage方法:每次接收到请求就在页面列表中加入一条数据;

<!DOCTYPE html>
<html>
<head><title>SSE test</title><script type="text/javascript">window.addEventListener("DOMContentLoaded", function () {var evsrc = new EventSource("/sse");evsrc.onmessage = function (ev) {document.getElementById("log").insertAdjacentHTML("beforeend", "<li>" + ev.data + "</li>");}evsrc.onerror = function (ev) {console.log("readyState = " + ev.currentTarget.readyState);}})</script>
</head>
<body>
<h1>SSE test</h1>
<div><ul id="log"></ul>
</div>
</body>
</html>

http://www.ppmy.cn/news/49715.html

相关文章

TryHackMe-Jack(boot2root)

Jack 破坏运行Wordpress的Web服务器&#xff0c;获得低特权用户&#xff0c;并使用Python模块将您的权限升级到root。 端口扫描 循例nmap web枚举 robots.txt wpscan枚举user wpscan直接爆 得到wendy的密码 直接登后台 根据题目提示&#xff0c;利用user role editor帮助我们…

第三十四章 配置镜像 - 在镜像中激活日志加密

文章目录 第三十四章 配置镜像 - 在镜像中激活日志加密在镜像中激活日志加密 第三十四章 配置镜像 - 在镜像中激活日志加密 在镜像中激活日志加密 在镜像成员上激活日志加密时&#xff0c;请记住三个重要的注意事项&#xff1a; 不能在故障转移成员和 DR 异步上激活日志文件加…

月获2万份简历,硕士占比超70%!中欧基金如何破圈打造雇主品牌?

成立于2006年的中欧基金&#xff0c;作为国内首批实现员工持股的基金公司&#xff0c;坚持以人为本&#xff0c;相信优秀的业绩要靠优秀的人才来创造。 因此&#xff0c;中欧基金在完善公司治理机制基础上&#xff0c;实现不仅有敢打硬仗能打胜仗的将才&#xff0c;还有更多不…

3、Typescript中补充的六个类型

1、元组 元组可以看做是数组的拓展&#xff0c;它表示已知元素数量和类型的数组。确切地说&#xff0c;是已知数组中每一个位置上的元素的 类型&#xff0c;来看例子&#xff1a; let tuple: [string, number, boolean]; tuple ["a", 2, false]; tuple [2, "…

PDD滑块分析

文章目录 1.流程分析2.关键点分析3.结果展示 声明&#xff1a;本文只作学习研究&#xff0c;禁止用于非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01; 欢迎大佬加群一起交流哇&#xff08; Q群&#xff1a;985475126…

ROS——Teb算法的优化

一、简介 “TEB”全称Time Elastic Band&#xff08;时间弹性带&#xff09;Local Planner&#xff0c;该方法针对全局路径规划器生成的初始轨迹进行后续修正(modification)&#xff0c;从而优化机器人的运动轨迹&#xff0c;属于局部路径规划。 关于eletic band&#xff08;橡…

MyBatis详解(2)

8、自定义映射resultMap 8.1、resultMap处理字段和属性的映射关系 若字段名和实体类中的属性名不一致&#xff0c;则可以通过resultMap设置自定义映射 <!--resultMap&#xff1a;设置自定义映射属性&#xff1a;id&#xff1a;表示自定义映射的唯一标识type&#xff1a;查询…

DAX:概述ALL函数

简单的说&#xff0c;当ALL用作表函数时&#xff0c;忽略应用到表上的任何过滤器&#xff0c;并返回数据表&#xff1b;当ALL用作CALCULATE和CALCULATETABLE函数中修饰器时&#xff0c;ALL函数从扩展表中移除已经应用的过滤上下文。 注意自动存在(auto-eixist)对ALL()函数的影响…