Response 的 Writer 扩展
Hertz 提供的 Response 的 Writer 扩展。
按照 Hertz 的 分层架构 设计,HTTP 响应实际的写操作是在应用层用户处理逻辑返回之后进行的。用户在这个限制下是不能够灵活按需控制写操作的行为的,这个限制在类似控制 chunk 分块编码写逻辑、SSE 的场景下尤为明显。
为了解决这个问题,Hertz 提供了一个叫做「Response Writer 劫持」扩展,它能够以正交的方式垂直打通分层架构所带来的写响应局限。让用户可以根据自己的需求在应用层自由的定制写响应的逻辑,提升框架易用性。
核心设计
接口定义
接口定义在 pkg/network/writer
.
type ExtWriter interface {
io.Writer
Flush() error
// Finalize will be called by framework before the writer is released.
// Implementations must guarantee that Finalize is safe for multiple calls.
Finalize() error
}
劫持 Response 的 Writer
Hertz 在 app.RequestContext
中提供了 Response.HijackWriter
方法让用户劫持 Response 的 Writer.
用法示例:
h.GET("/hijack", func(c context.Context, ctx *app.RequestContext) {
// Hijack the writer of Response
ctx.Response.HijackWriter(**yourResponseWriter**)
})
已支持 Response 的 Writer 扩展
ChunkedBodyWriter
:Hertz 在pkg/protocol/http1/resp/writer
下默认提供了NewChunkedBodyWriter
方法来创建一个 Response 的 Writer,它允许用户在 Handler 中立即刷新分块,用户也可以实现自己的 Response 的 Writer。
ChunkedBodyWriter
用法示例:
h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) {
// Hijack the writer of Response
ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter()))
for i := 0; i < 10; i++ {
ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck
ctx.Flush() // nolint: errcheck
time.Sleep(200 * time.Millisecond)
}
})
效果展示:
在 localhost:8888 开启示例中的接口,然后使用如下命令观察效果:
curl -N --location localhost:8888/flush/chunk
最后修改
January 18, 2024
: Upload volo blog (#936) (1fc8abb)