🌀

GoでHTTP Streaming

2022/07/27に公開

概要

WebSocketやHTTP/2を使わず、レスポンスをストリームで受け取ることができる

実装

server

server.go
package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"time"
)

func stream(w http.ResponseWriter, r *http.Request) {
	flusher, _ := w.(http.Flusher)
	cw := httputil.NewChunkedWriter(w)
	for i := 0; i < 3; i++ {
		cw.Write([]byte("hello"))
		flusher.Flush()
		time.Sleep(time.Second)
	}
}

func main() {
	http.HandleFunc("/", stream)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
$ go run server.go

$ curl localhost:8080 -i
HTTP/1.1 200 OK
Date: Wed, 27 Jul 2022 02:00:48 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked

5
hello
5
hello
5
hello

client

client.go
package main

import (
	"io"
	"log"
	"net/http"
	"net/http/httputil"
)

func main() {
	resp, err := http.Get("http://localhost:8080")
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		log.Fatal(resp.Status)
	}
	cr := httputil.NewChunkedReader(resp.Body)
	for {
		buf := make([]byte, 5)
		n, err := cr.Read(buf)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		log.Println(string(buf[:n]))
	}
}
$ go run client.go
2022/07/27 11:04:50 hello
2022/07/27 11:04:51 hello
2022/07/27 11:04:52 hello

参考

https://qiita.com/Gatz/items/dc08b13e982e6a3d5043
https://gist.github.com/vmarmol/b967b29917a34d9307ce

Discussion