Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions content/en/blog/releases/Hertz/release-v0_10_0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: "Hertz Release v0.10.0"
linkTitle: "Release v0.10.0"
projects: ["Hertz"]
date: 2025-05-21
description: >
---

The Hertz v0.10.0 release adds two features and some fixes.

1. Integrate SSE functionality. Refer to [SSE](/docs/hertz/tutorials/basic-feature/sse) for usage.
2. Added http.Handler adaptor, extending Hertz using the official net/http ecosystem. Refer to [Adaptor](/docs/hertz/tutorials/basic-feature/http-adaptor) for usage.

## Feature
1. [[#1327](https://github.com/cloudwego/hertz/pull/1327)] feat(adaptor): new HertzHandler for http.Handler
2. [[#1349](https://github.com/cloudwego/hertz/pull/1349)] feat(sse): SetLastEventID
3. [[#1343](https://github.com/cloudwego/hertz/pull/1343)] feat(sse): reader supports cancel stream
4. [[#1341](https://github.com/cloudwego/hertz/pull/1341)] feat(server): detect request race
5. [[#1339](https://github.com/cloudwego/hertz/pull/1339)] feat(sse): add LastEventID helpers
6. [[#1335](https://github.com/cloudwego/hertz/pull/1335)] feat(protocol): new sse pkg
7. [[#1322](https://github.com/cloudwego/hertz/pull/1322)] feat: std transport sense client connection close

## Fix
1. [[#1340](https://github.com/cloudwego/hertz/pull/1340)] fix: only use netpoll & sonic on amd64/arm64 linux/darwin
2. [[#1333](https://github.com/cloudwego/hertz/pull/1333)] fix(protocol): unexpected set resp.bodyStream
3. [[#1329](https://github.com/cloudwego/hertz/pull/1329)] fix(client): stream body for sse instead of timeout
4. [[#1332](https://github.com/cloudwego/hertz/pull/1332)] fix(server): Shutdown checks ExitWaitTimeout
5. [[#1316](https://github.com/cloudwego/hertz/pull/1316)] fix: prioritize custom validator

## Tests
1. [[#1336](https://github.com/cloudwego/hertz/pull/1336)] test(protocol): fix hardcoded listen addr

## Chore
1. [[#1353](https://github.com/cloudwego/hertz/pull/1353)] chore: update netpoll dependency
2. [[#1337](https://github.com/cloudwego/hertz/pull/1337)] chore(hz): update hz tool v0.9.7
3. [[#1328](https://github.com/cloudwego/hertz/pull/1328)] ci: disable codecov annotations
2 changes: 2 additions & 0 deletions content/en/docs/hertz/tutorials/basic-feature/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ keywords:
"Constants",
"Render",
"JSON Marshal Library",
"SSE",
"http.Handler adaptor",
]
description: "Basic feature of Hertz."
---
50 changes: 50 additions & 0 deletions content/en/docs/hertz/tutorials/basic-feature/http-adaptor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "http.Handler adaptor"
date: 2025-05-21
weight: 20
keywords: ["adaptor"]
description: ""
---

## Background

- Phasing out the poorly maintained hertz app.FS implementation
- Providing a compatible and performant fs implementation through the official net/http ecosystem
- Extending hertz functionality through the official net/http ecosystem to reduce custom implementations

## What is adaptor.HertzHandler

- Allows you to convert existing http.HandlerFunc methods directly to HertzHandler
- Enables direct use of standard library methods like http.FileServer and embed.FS
- Even allows direct use of github.com/gorilla/websocket in Hertz

## Example

```go
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()
}
```
107 changes: 107 additions & 0 deletions content/en/docs/hertz/tutorials/basic-feature/sse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: "SSE"
date: 2025-05-21
weight: 19
keywords: ["SSE"]
description: "SSE capabilities provided by Hertz"
---
```code: https://github.com/cloudwego/hertz/tree/develop/pkg/protocol/sse```

## What is Server-Sent Events (SSE)

- SSE is an HTML standard used to describe the implementation of browser EventSource API. Strictly speaking, it's not an HTTP protocol.
- Popular protocols like Model Context Protocol (MCP) or Agent2Agent (A2A) are based on SSE to some extent
- https://www.anthropic.com/news/model-context-protocol
- https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/

## Server-side Implementation

### Returning Data

```go
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() // Send the last chunk of data to ensure graceful exit. Optional, Hertz will automatically call it after the Handler returns.

// Please ensure the writer's lifecycle is consistent with the handler. Don't use it asynchronously in the background.
}
```

### Common Issues

#### connection has been closed when flush

Reason:
Client connection is disconnected, possibly due to no response data for too long. Please check the relevant configuration.

## Client-side Implementation

### Initiating a Request

It's exactly the same as initiating a regular HTTP request with Hertz.

Note: New Hertz versions will automatically identify SSE streams, so you don't need to explicitly set WithResponseBodyStream(true)

**Some Optional Headers**

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

sse.AddAcceptMIME(req) // Some SSE Servers may require explicitly adding Accept: text/event-stream
sse.SetLastEventID(req, "id-123") // For stateful services, you need to tell the Server through SetLastEventID
```

### Handling Responses

```go
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
}

// You can also manually call the r.Read method
err = r.ForEach(ctx, func(e *Event) error {
println("Event:", e.String())
return nil
})
if err != nil { // If the Server disconnects normally, err == nil, no error will be reported
// Other IO errors or ctx cancelled
return err
}
println("Client LastEventID", r.LastEventID()) // Can be used to save the last received Event ID
return nil
}
```

### Common Issues

#### How to implement multi-level SSE / SSE Proxy?

- You can refer to both Client-side and Server-side implementations
- Enable `WithSenseClientDisconnection` on the Server and pass the context to the next hop's Reader ForEach
- This way, when the Client disconnects, it will be automatically detected and the entire stream will be interrupted

## Event Structure

```go
// Event represents a Server-Sent Event (SSE).
type Event struct {
ID string // This is the Event ID, sse.Reader will automatically record the last Event ID, which can be obtained using LastEventID()
Type string // This is the Event Type, common ones like "message"
Data []byte // For convenience with Unmarshal/Marshal, []byte is used here, but according to the spec, this field must be a utf8 string

// Not recommended to use, mainly for controlling the retry strategy of the browser's SourceEvent.
// If using Hertz as a Client, you can refer to: https://www.cloudwego.io/docs/hertz/tutorials/basic-feature/retry/
Retry time.Duration
}
```
36 changes: 36 additions & 0 deletions content/zh/blog/releases/Hertz/release-v0_10_0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: "Hertz Release v0.10.0"
linkTitle: "Release v0.10.0"
projects: ["Hertz"]
date: 2025-05-21
description: >
---

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

1. 集成 SSE 功能。使用方法请参阅 [SSE](/docs/hertz/tutorials/basic-feature/sse)。
2. 添加 http.Handler 适配器,使用官方 net/http 生态系统扩展 Hertz。使用方法请参阅 [Adaptor](/docs/hertz/tutorials/basic-feature/http-adaptor)。

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

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

## Tests
1. [[#1336](https://github.com/cloudwego/hertz/pull/1336)] test(protocol): 修复硬编码的监听地址

## Chore
1. [[#1353](https://github.com/cloudwego/hertz/pull/1353)] chore:更新 netpoll 依赖
2. [[#1337](https://github.com/cloudwego/hertz/pull/1337)] chore(hz): 更新 hz 工具 v0.9.7
3. [[#1328](https://github.com/cloudwego/hertz/pull/1328)] ci: 禁用 codecov 注释
2 changes: 2 additions & 0 deletions content/zh/docs/hertz/tutorials/basic-feature/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ keywords:
"常量",
"渲染",
"JSON Marshal 库",
"SSE",
"http.Handler adaptor",
]
description: "Hertz 基本特性。"
---
50 changes: 50 additions & 0 deletions content/zh/docs/hertz/tutorials/basic-feature/http-adaptor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "http.Handler adaptor"
date: 2025-05-21
weight: 20
keywords: ["adaptor"]
description: ""
---

## 背景

- 淘汰长期没有良好维护的 hertz app.FS 实现
- 通过官方 net/http 生态提供一个兼容性较好,性能也不差的 fs 实现。
- 通过官方 net/http 生态扩展 hertz 功能,减少大量扩展实现

## 什么是 adaptor.HertzHandler

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

## 具体例子

```go
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()
}
```
Loading