LoginSignup
1
0

More than 5 years have passed since last update.

http.Response.Bodyちゃん行方不明事件

Posted at

適当なエンドポイントにアクセスして、レスポンスボディを読んで、更に他にも利用しようとします。

func badFunc() {
    // httpRequestは、http.Client.GetのWrapper
    resp, err := httpRequest("https://httpbin.org/")
    if err != nil {
        log.Fatal(err.Error())
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    // 中略

    // スクレイピング
    data, err := scrap(resp.Body)
    // 以下、省略
}

一見問題なさそうにみえますが、実はこれは正常に動きません。
ioutil.ReadAll(resp.Body)が動いた段階で、resp.Body の中が空になってしまうからです。これによって、後続のスクレイピングの処理は空データをスクレイピングしようとするのでエラー扱いになります。
(というか、独自処理なので、エラー扱いにしますといったほうが正しいかも)

結論から先にいうと、下記のようにしてしまえば解決します。
違いは、ioutil.ReadAll(resp.Body)の後に、resp.Bodyにレスポンス入れ直しているところ。これで、後続処理も正しく動くようになります。

func goodFunc() {
    // httpRequestは、http.Client.GetのWrapper
    resp, err := httpRequest("https://httpbin.org/")
    if err != nil {
        log.Fatal(err.Error())
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    // 中略

    // ioutil.ReadAllの時点で消失してしまうので
    resp.Body = ioutil.NopCloser(bytes.NewBuffer(body))

    // スクレイピング
    data, err := scrap(resp.Body)
    // 以下、省略
}

メモリリークしたりするとこの現象が起こるらしいですが、そんなことが起きているわけでもなさそうなので、原因はよくわかりません。ソース読んでも、Stackoverflowとか見ても解決方法は書いてても、この現象の原因みたいなのはわかりませんでした。
(わかったら追記します)

とりあえず、http.Response.Bodyちゃんはきちんとお家に帰ってきましたとさ。
めでたしめでたし

1
0
0

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
1
0