GoNote第六章 GoFrame 接入SSE

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 main

import (
	"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!")
				return
			default:
				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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好奇新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值