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を返すエンドポイントを追加しています。このサーバを今後は監視にも利用していくつもりです。