Go net/httpで任意のタイミングでchunked レスポンスを返す
調査のため、chunked レスポンスを行っている合間に遅延をいれる必要があったので、Go net/httpでの実現方法を調べました。
こちらにあった Flusher.Flush()
を使うことになります。
FizzBuzzっぽいものを遅延をいれつつ書き出すにはこんな感じ
func fizzBuzz(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { w.WriteHeader(500) w.Write([]byte("expected http.ResponseWriter to be an http.Flusher")) return } for i := 1; i <= 15; i++ { p := fmt.Sprintf("#%03d ", i) if i%3 == 0 { p += "Fizz" } if i%5 == 0 { p += "Buzz" } p = strings.TrimSpace(p) p += "\n" w.Write([]byte(p)) flusher.Flush() time.Sleep(300 * time.Millisecond) } }
telnetで試すと意図した通り chunk に分かれてレスポンスされてくるのがわかる
]% telnet localhost 3000 Trying ::1... Connected to localhost. Escape character is '^]'. GET /demo/fizzbuzz_stream HTTP/1.1 Host: example.com HTTP/1.1 200 OK Vary: Accept-Encoding Date: Wed, 10 Mar 2021 01:46:27 GMT Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked 5 #001 5 #002 a #003 Fizz 5 #004 a #005 Buzz a #006 Fizz 5 #007 5 #008
このFlushは github.com/NYTimes/gziphandler
にて圧縮をかけていても有効でした。
gziphandlerの簡単な使い方
// fizzbuzzのためMinSizeを小さくしておく。デフォルト 1400 gz, _ := gziphandler.NewGzipLevelAndMinSize(gzip.DefaultCompression, 5) http.Handle("/", gz(http.HandlerFunc(fizzBuzz)))
テスト・検証用で作っている http-dump-request というサーバにこのFizzBuzzを返すエンドポイントを追加しています。このサーバを今後は監視にも利用していくつもりです。