Hertz v0.10.0 发布--内置支持服务端发送事件(SSE)协议

发布于:2025-06-27 ⋅ 阅读:(17) ⋅ 点赞:(0)

Hertz v0.10.0 版本新增两项重要功能并修复了一些问题。

1. SSE 协议支持

SSE(Server-Sent Events) 是一种允许服务器主动向浏览器推送实时数据的技术。它基于普通的 HTTP 协议,适合需要服务器单向发送消息的场景(比如新闻推送、股票价格更新、实时通知等)。

SSE 天然支持服务器向客户端的单向数据流,当大语言模型需要实时获取文档更新、工具调用结果时,SSE 无需客户端轮询即可实现事件驱动的数据推送。因此目前流行大语言模型的 MCP (Model Context Protocol) 或 A2A (Agent2Agent) 协议都依赖于 SSE 协议。

Server 端实现

返回数据

import "github.com/cloudwego/hertz/pkg/protocol/sse"

func HandleSSE(ctx context.Context, c *app.RequestContext) {
    println("Server Got LastEventID", sse.GetLastEventID(&c.Request))
    w := sse.NewWriter(c)
    for i := 0; i < 5; i++ {
        w.WriteEvent("id-x""message", []byte("hello\n\nworld"))
        time.Sleep(10 * time.Millisecond)
    }
    w.Close() // 发送最后的 chunk 数据,确保优雅退出。可选,Hertz 在 Handler 返回后会自动调用。

    // 请确保 writer 的生命周期和 handler 一致。不要 go 异步后台使用。
}

Client 端实现

发起请求

与正常 Hertz 发起一个普通的 http 请求完全一致。

注意:新 hertz 版本会自动识别 SSE 流,不用显式设置 WithResponseBodyStream(true)

部分可选 Header

import "github.com/cloudwego/hertz/pkg/protocol/sse"

sse.AddAcceptMIME(req) // 部分 SSE Server 可能会要求显式增加 Accept: text/event-stream
sse.SetLastEventID(req, "id-123"// 对于有状态服务,需要通过 SetLastEventID 告诉 Server

处理返回

import "github.com/cloudwego/hertz/pkg/protocol/sse"

func HandleSSE(ctx context.Context, resp *protocol.Response) error {
    r, err := sse.NewReader(resp)
    if err != nil {
    return err
    }

    // 也可以手动调用 r.Read 方法
    err = r.ForEach(ctx, func(e *Event) error {
        println("Event:", e.String())
        return nil
    })
    if err != nil { // 如果 Server 正常断开,这里 err == nil,不会报错
        // 其他 io 错误 或 ctx cancelled
        return err
    }
    println("Client LastEventID", r.LastEventID()) // 可用于保存最后接收的 Event ID
    return nil
}

在Hertz中使用SSE方法请参阅 https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/sse/。

2. 适配器

添加 http.Handler 适配器,使用官方 net/http 生态系统扩展 Hertz。

  • 允许用户将现有的 http.HandlerFunc 方法直接转为 HertzHandler。
  • 同时可以直接使用 http.FileServer embed.FS 等标准库方法
  • 甚至可以直接在 Hertz 使用 github.com/gorilla/websocket

具体例子

package main

import (
  "embed"
  "net/http"

  "github.com/cloudwego/hertz/pkg/app/server"
  "github.com/cloudwego/hertz/pkg/common/adaptor"
)

//go:embed static/*
var staticFiles embed.FS

func main() {
  h := server.Default()

  helloHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello hertz!"))
  })
  h.GET("/hello", adaptor.HertzHandler(helloHandler))

  staticFS := adaptor.HertzHandler(http.FileServer(http.FS(staticFiles)))
  h.GET("/static/*filepath", staticFS)
  h.HEAD("/static/*filepath", staticFS)
  h.Spin()
}

详细变更

Feature

  1. #1327 feat(adaptor): 为 http.Handler 添加新的 HertzHandler
  2. #1349 feat(sse): SetLastEventID
  3. #1343 feat(sse): reader 支持取消流
  4. #1341 feat(server): 检测请求 race
  5. #1339 feat(sse): 添加 LastEventID helper
  6. #1335 feat(protocol): 新的 sse 包
  7. #1322 feat: server 使用标准 go net 传输时感知客户端连接关闭

Fix

  1. #1340 fix:仅在 amd64/arm64 linux/darwin 上使用 netpoll 和 sonic
  2. #1333 fix(protocol): 非预期的设置 resp.bodyStream
  3. #1329 fix(client): sse 场景下自动切换为 stream body 模式
  4. #1332 fix(server): server 关闭时检查 ExitWaitTimeout
  5. #1316 fix: 优先使用自定义 validator

Tests

  1. #1336 test(protocol): 修复硬编码的监听地址

Chore

  1. #1353 chore:更新 netpoll 依赖
  2. #1337 chore(hz): 更新 hz 工具 v0.9.7
  3. #1328 ci: 禁用 codecov 注释

本文由 mdnice 多平台发布


网站公告

今日签到

点亮在社区的每一天
去签到