LoginSignup
12

More than 5 years have passed since last update.

GoでHTTP Trailerを扱う

Last updated at Posted at 2015-03-10

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]]

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12