CloudWeGo 是一套由字节跳动基础架构服务框架团队开源的、可快速构建企业级云原生微服务架构的中间件集合。SSE(Server-Sent Events)是CloudWeGo项目下Hertz脚手架中的HTTP通用中间件,是一种服务器推送技术,它允许服务器端通过简单的 HTTP 响应向客户端发送事件。
环境与应用
在基于Golang的微服务中间件应用中使用,目前作为字节跳动微服务框架Hertz的主要http通讯方式
安装
go get github.com/hertz-contrib/sse
示例代码
服务端 Server
在下面的示例中,在访问 /sse
时,服务端将每秒向客户端推送一个时间戳。
package main
import (
"context"
"net/http"
"time"
"github.com/hertz-contrib/sse"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/hlog"
)
func main() {
h := server.Default()
h.GET("/sse", func(ctx context.Context, c *app.RequestContext) {
// 客户端可以通过 Last-Event-ID 告知服务器收到的最后一个事件
lastEventID := sse.GetLastEventID(c)
hlog.CtxInfof(ctx, "last event ID: %s", lastEventID)
// 在第一次渲染调用之前必须先行设置状态代码和响应头文件
c.SetStatusCode(http.StatusOK)
s := sse.NewStream(c)
for t := range time.NewTicker(1 * time.Second).C {
event := &sse.Event{
Event: "timestamp",
Data: []byte(t.Format(time.RFC3339)),
}
err := s.Publish(event)
if err != nil {
return
}
}
})
h.Spin()
}
客户端 Client
package main
import (
"context"
"sync"
"github.com/hertz-contrib/sse"
"github.com/cloudwego/hertz/pkg/common/hlog"
)
var wg sync.WaitGroup
func main() {
wg.Add(2)
go func() {
// 传入 server 端 URL 初始化客户端
c := sse.NewClient("http://127.0.0.1:8888/sse")
// 连接到服务端的时候触发
c.OnConnect(func(ctx context.Context, client *sse.Client) {
hlog.Infof("client1 connect to server %s success with %s method", c.URL, c.Method)
})
// 服务端断开连接的时候触发
c.OnDisconnect(func(ctx context.Context, client *sse.Client) {
hlog.Infof("client1 disconnect to server %s success with %s method", c.URL, c.Method)
})
events := make(chan *sse.Event)
errChan := make(chan error)
go func() {
cErr := c.Subscribe(func(msg *sse.Event) {
if msg.Data != nil {
events <- msg
return
}
})
errChan <- cErr
}()
for {
select {
case e := <-events:
hlog.Info(e)
case err := <-errChan:
hlog.CtxErrorf(context.Background(), "err = %s", err.Error())
wg.Done()
return
}
}
}()
go func() {
// 传入 server 端 URL 初始化客户端
c := sse.NewClient("http://127.0.0.1:8888/sse")
// 连接到服务端的时候触发
c.OnConnect(func(ctx context.Context, client *sse.Client) {
hlog.Infof("client2 %s connect to server success with %s method", c.URL, c.Method)
})
// 服务端断开连接的时候触发
c.OnDisconnect(func(ctx context.Context, client *sse.Client) {
hlog.Infof("client2 %s disconnect to server success with %s method", c.URL, c.Method)
})
events := make(chan *sse.Event)
errChan := make(chan error)
go func() {
cErr := c.Subscribe(func(msg *sse.Event) {
if msg.Data != nil {
events <- msg
return
}
})
errChan <- cErr
}()
for {
select {
case e := <-events:
hlog.Info(e)
case err := <-errChan:
hlog.CtxErrorf(context.Background(), "err = %s", err.Error())
wg.Done()
return
}
}
}()
select {}
}
SSE vs Websocket
WebSocket 是基于独立的 TCP 连接实现的,使用自定义的协议。客户端和服务器之间可以建立持久的全双工通信的连接,可以双向发送和接收数据。
差异
SSE 适用于服务器向客户端单向发送实时更新的数据,适合实时事件推送场景。SSE 使用的是标准的 HTTP 协议,对于浏览器的兼容性较好,但只支持客户端接收数据。
WebSocket 适用于客户端和服务器之间的双向实时通信,适合聊天应用、实时游戏等场景。WebSocket 需要独立的 TCP 连接,因此相比 SSE,会增加一定的网络开销,但能够实现双向通信。
适用场景
SSE 适用于需要服务器向客户端单向实时推送数据的场景,例如实时更新的新闻、股票行情等。
优点:简单易用,对服务器压力小,浏览器兼容性好。
缺点:只支持单向通信,无法进行双向交互。
WebSocket 适用于需要客户端和服务器之间实时双向通信的场景,例如聊天室、实时协作应用等。
优点:支持双向通信,实时性更高,可以实现更丰富的交互效果。
缺点:需要独立的 TCP 连接,对服务器压力更大,浏览器兼容性相对较差。
官方参考文档:https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/protocol/sse/
评论区