Skip to content

Commit

Permalink
docs: update extWriter (#786)
Browse files Browse the repository at this point in the history
  • Loading branch information
welkeyever authored Sep 22, 2023
1 parent 51eb134 commit 71c7226
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 33 deletions.
63 changes: 38 additions & 25 deletions content/en/docs/hertz/tutorials/framework-exten/response_writer.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,73 @@
---
title: "Response Writer Extension"
linkTitle: "Response Writer Extension"
date: 2023-03-10
date: 2023-09-22
weight: 6
keywords: ["Response Writer Extension", "Response.HijackWriter"]
keywords: [ "Response Writer Extension", "Response.HijackWriter" ]
description: "Response Writer Extension provided by Hertz."

---

Hertz provides response writer extension, if users need to hijack the writer of the response, they can implement the corresponding interfaces according to their needs.
According to Hertz's [layered architecture](https://www.cloudwego.io/zh/docs/hertz/overview/), the actual write
operation of the HTTP response is performed after the application layer user processing logic returns. Under this
constraint, users cannot flexibly control the behavior of write operations on demand. This limitation is especially
obvious in scenarios such as controlling chunked encoding write logic
and [SSE](https://github.com/hertz-contrib/sse#hertz-sse).

## Interface Definition
To solve this problem, Hertz provides an extension called "Response Writer Hijacking" that can vertically penetrate the
limitations brought by the layered architecture in an orthogonal way. It allows users to freely customize the logic of
writing responses in the application layer according to their own needs, improving the framework's ease of use.

## Core Design

### Interface Definition

interface is defined in `pkg/network/writer`.

```go
type ExtWriter interface {
io.Writer
Flush() error
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
// Finalize will be called by framework before the writer is released.
// Implementations must guarantee that Finalize is safe for multiple calls.
Finalize() error
}
```

### Hijack Your Own Response Writer

Hertz provides `Response.HijackWriter` in `app.RequestContext` to allow users to hijack their own response writer, which provides another way for response writing process.
Hertz provides `Response.HijackWriter` in `app.RequestContext` to allow users to hijack their own response writer, which
provides another way for response writing process.

Example:

```go
h.GET("/hijack", func(c context.Context, ctx *app.RequestContext) {
// Hijack the writer of response
ctx.Response.HijackWriter(yourResponseWriter)
})
h.GET("/hijack", func (c context.Context, ctx *app.RequestContext) {
// Hijack the writer of response
ctx.Response.HijackWriter(**yourResponseWriter**)
})
```

## Supported Response Writer Extension

Hertz provides `NewChunkedBodyWriter` to create a response writer which allow users to flush chunk immediately during the handler process, it is defined under `pkg/protocol/http1/resp/writer`, and you can implement your own response writer.
- `ChunkedBodyWriter`: Hertz provides `NewChunkedBodyWriter` to create a response writer which allow users to flush chunk immediately during
the handler process, it is defined under `pkg/protocol/http1/resp/writer`, and you can implement your own response
writer.

### ChunkedBodyWriter

Example:

```go
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)
}
})
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)
}
})
```
20 changes: 12 additions & 8 deletions content/zh/docs/hertz/tutorials/framework-exten/response_writer.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
---
title: "Response 的 Writer 扩展"
linkTitle: "Response 的 Writer 扩展"
date: 2023-03-10
date: 2023-09-22
weight: 6
keywords: ["Response 的 Writer 扩展", "Response.HijackWriter"]
description: "Hertz 提供的 Response 的 Writer 扩展。"

---

Hertz 提供了 response 的 writer 扩展,用户可以根据自己的需要实现相应的接口去劫持 response 的 writer
按照 Hertz [分层架构](https://www.cloudwego.io/zh/docs/hertz/overview/)设计,HTTP 响应实际的写操作是在应用层用户处理逻辑返回之后进行的。用户在这个限制下是不能够灵活按需控制写操作的行为的,这个限制在类似控制 chunk 分块编码写逻辑、[SSE](https://github.com/hertz-contrib/sse#hertz-sse) 的场景下尤为明显

## 接口定义
为了解决这个问题,Hertz 提供了一个叫做「Response Writer 劫持」扩展,它能够以正交的方式垂直打通分层架构所带来的写响应局限。让用户可以根据自己的需求在应用层自由的定制写响应的逻辑,提升框架易用性。

## 核心设计

### 接口定义

接口定义在 `pkg/network/writer`.

Expand All @@ -27,28 +31,28 @@ type ExtWriter interface {

### 劫持 Response 的 Writer

Hertz 在 `app.RequestContext` 中提供了 `Response.HijackWriter` 方法让用户劫持 responsewriter.
Hertz 在 `app.RequestContext` 中提供了 `Response.HijackWriter` 方法让用户劫持 ResponseWriter.

用法示例:

```go
h.GET("/hijack", func(c context.Context, ctx *app.RequestContext) {
// Hijack the writer of response
ctx.Response.HijackWriter(yourResponseWriter)
// Hijack the writer of Response
ctx.Response.HijackWriter(**yourResponseWriter**)
})
```

## 已支持 Response 的 Writer 扩展

Hertz 在 `pkg/protocol/http1/resp/writer` 下提供了 `NewChunkedBodyWriter` 方法来创建一个 responsewriter,它允许用户在 handler 中立即刷新分块,用户也可以实现自己的 responsewriter
- `ChunkedBodyWriter`Hertz 在 `pkg/protocol/http1/resp/writer` 下默认提供了 `NewChunkedBodyWriter` 方法来创建一个 ResponseWriter,它允许用户在 Handler 中立即刷新分块,用户也可以实现自己的 ResponseWriter

### ChunkedBodyWriter

用法示例:

```go
h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) {
// Hijack the writer of response
// Hijack the writer of Response
ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter()))

for i := 0; i < 10; i++ {
Expand Down

1 comment on commit 71c7226

@vercel
Copy link

@vercel vercel bot commented on 71c7226 Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.