|
1 | 1 | ---
|
2 | 2 | title: "Response Writer Extension"
|
3 | 3 | linkTitle: "Response Writer Extension"
|
4 |
| -date: 2023-03-10 |
| 4 | +date: 2023-09-22 |
5 | 5 | weight: 6
|
6 |
| -keywords: ["Response Writer Extension", "Response.HijackWriter"] |
| 6 | +keywords: [ "Response Writer Extension", "Response.HijackWriter" ] |
7 | 7 | description: "Response Writer Extension provided by Hertz."
|
8 | 8 |
|
9 | 9 | ---
|
10 | 10 |
|
11 |
| -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. |
| 11 | +According to Hertz's [layered architecture](https://www.cloudwego.io/zh/docs/hertz/overview/), the actual write |
| 12 | +operation of the HTTP response is performed after the application layer user processing logic returns. Under this |
| 13 | +constraint, users cannot flexibly control the behavior of write operations on demand. This limitation is especially |
| 14 | +obvious in scenarios such as controlling chunked encoding write logic |
| 15 | +and [SSE](https://github.com/hertz-contrib/sse#hertz-sse). |
12 | 16 |
|
13 |
| -## Interface Definition |
| 17 | +To solve this problem, Hertz provides an extension called "Response Writer Hijacking" that can vertically penetrate the |
| 18 | +limitations brought by the layered architecture in an orthogonal way. It allows users to freely customize the logic of |
| 19 | +writing responses in the application layer according to their own needs, improving the framework's ease of use. |
| 20 | + |
| 21 | +## Core Design |
| 22 | + |
| 23 | +### Interface Definition |
14 | 24 |
|
15 | 25 | interface is defined in `pkg/network/writer`.
|
16 | 26 |
|
17 | 27 | ```go
|
18 | 28 | type ExtWriter interface {
|
19 |
| - io.Writer |
20 |
| - Flush() error |
| 29 | +io.Writer |
| 30 | +Flush() error |
21 | 31 |
|
22 |
| - // Finalize will be called by framework before the writer is released. |
23 |
| - // Implementations must guarantee that Finalize is safe for multiple calls. |
24 |
| - Finalize() error |
| 32 | +// Finalize will be called by framework before the writer is released. |
| 33 | +// Implementations must guarantee that Finalize is safe for multiple calls. |
| 34 | +Finalize() error |
25 | 35 | }
|
26 | 36 | ```
|
27 | 37 |
|
28 | 38 | ### Hijack Your Own Response Writer
|
29 | 39 |
|
30 |
| -Hertz provides `Response.HijackWriter` in `app.RequestContext` to allow users to hijack their own response writer, which provides another way for response writing process. |
| 40 | +Hertz provides `Response.HijackWriter` in `app.RequestContext` to allow users to hijack their own response writer, which |
| 41 | +provides another way for response writing process. |
31 | 42 |
|
32 | 43 | Example:
|
33 | 44 |
|
34 | 45 | ```go
|
35 |
| - h.GET("/hijack", func(c context.Context, ctx *app.RequestContext) { |
36 |
| - // Hijack the writer of response |
37 |
| - ctx.Response.HijackWriter(yourResponseWriter) |
38 |
| - }) |
| 46 | + h.GET("/hijack", func (c context.Context, ctx *app.RequestContext) { |
| 47 | +// Hijack the writer of response |
| 48 | +ctx.Response.HijackWriter(**yourResponseWriter**) |
| 49 | +}) |
39 | 50 | ```
|
40 | 51 |
|
41 | 52 | ## Supported Response Writer Extension
|
42 | 53 |
|
43 |
| -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. |
| 54 | +- `ChunkedBodyWriter`: Hertz provides `NewChunkedBodyWriter` to create a response writer which allow users to flush chunk immediately during |
| 55 | +the handler process, it is defined under `pkg/protocol/http1/resp/writer`, and you can implement your own response |
| 56 | +writer. |
44 | 57 |
|
45 | 58 | ### ChunkedBodyWriter
|
46 | 59 |
|
47 | 60 | Example:
|
48 | 61 |
|
49 | 62 | ```go
|
50 |
| - h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { |
51 |
| - // Hijack the writer of response |
52 |
| - ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter())) |
53 |
| - |
54 |
| - for i := 0; i < 10; i++ { |
55 |
| - ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck |
56 |
| - ctx.Flush() // nolint: errcheck |
57 |
| - time.Sleep(200 * time.Millisecond) |
58 |
| - } |
59 |
| - }) |
| 63 | + h.GET("/flush/chunk", func (c context.Context, ctx *app.RequestContext) { |
| 64 | +// Hijack the writer of response |
| 65 | +ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter())) |
| 66 | + |
| 67 | +for i := 0; i < 10; i++ { |
| 68 | +ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck |
| 69 | +ctx.Flush() // nolint: errcheck |
| 70 | +time.Sleep(200 * time.Millisecond) |
| 71 | +} |
| 72 | +}) |
60 | 73 | ```
|
0 commit comments