侧边栏壁纸
  • 累计撰写 53 篇文章
  • 累计创建 12 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

流式http——SSE

Kirito
2024-03-30 / 0 评论 / 0 点赞 / 38 阅读 / 5496 字 / 正在检测是否收录...

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/

0

评论区