HTTP Trailer
Goのnet/http
パッケージはHTTP Trailerの送信および受信に対応しています。Trailerとは、HTTPリクエストBodyの末尾に付与できるヘッダと同様の構造です。Transfer-Encoding: chunked
のときのみ利用可能で、Body送信後にしか分からないチェックサムなどをリクエストに付与したいときに便利です。
なお、Go 1.4時点ではサーバレスポンスへのTrailer付与には対応していないようです(Hijackすれば可能)。
使い方
HTTPクライアントリクエスト側でのポイントは以下の通りです
- リクエストを
TransferEncoding: chunked
に設定する- req.ContentLength = 0 or -1 でも設定可
- 送信する前に
req.Trailer
をアロケーションしておく - 送信後、BodyがEOFになる前のタイミングで
req.Trailer
にTrailerを設定する
HTTPサーバーリクエスト側でのポイントは以下の通りです
- リクエストボディを読み終わったあとで
r.Trailer
を参照する
まとめると、以下の例のように扱うことができます
Example
package main
import (
"io"
"io/ioutil"
"log"
"net/http"
)
var ch = make(chan bool, 0)
func Handler(w http.ResponseWriter, r *http.Request) {
log.Println(r.Header)
log.Println(r.Trailer) // <- r.Bodyを読む前はTrailerを取得できない
io.Copy(ioutil.Discard, r.Body) // <- r.Bodyを読み込み
log.Println(r.Trailer) // <- 読み終わったので取得できる
w.WriteHeader(http.StatusOK)
ch <- true
}
func main() {
// サーバ起動
http.HandleFunc("/", Handler)
go http.ListenAndServe(":8080", nil)
// リクエスト発行
r, w := io.Pipe()
req, _ := http.NewRequest("PUT", "http://localhost:8080/test", r)
req.TransferEncoding = []string{"chunked"} // <- TransferEncoding: chunked を設定
req.Trailer = make(http.Header)
go http.DefaultClient.Do(req)
io.WriteString(w, "THIS IS A REQUEST BODY")
req.Trailer.Set("XXX", "my-trailer") // <- Close前にTrailerをセット
w.Close()
// blocking...
<-ch
}
結果は以下の通りです
2015/03/10 18:03:13 map[]
2015/03/10 18:03:13 map[Xxx:[my-trailer]]