LoginSignup
10
8

More than 5 years have passed since last update.

Go1.5以降でのnet/http Requestの新しいキャンセル方法

Last updated at Posted at 2016-06-06

net/http/#Transport.CancelRequest

func (t *Transport) CancelRequest(req *Request)

CancelRequest cancels an in-flight request by closing its connection. CancelRequest should only be called after RoundTrip has returned.

Deprecated: Use Request.Cancel instead. CancelRequest can not cancel HTTP/2 requests.

久しぶりにガッツリGoを書いていて気づいたのですが、Transport.CancelRequest()メソッドがDeprecatedになっていました。代わりにRequest.Cancelを使えとのこと。Request.CancelはGo1.5で追加されたらしい1

net/http/#Request

type Request struct {

        // Cancel is an optional channel whose closure indicates that the client
        // request should be regarded as canceled. Not all implementations of
        // RoundTripper may support Cancel.
        //
        // For server requests, this field is not applicable.
        Cancel <-chan struct{}
}

Request構造体のドキュメントを見てみると確かにCancelフィールドが追加されています。Request.Cancelにchan struct{}型のチャネルを代入しておいて、そのチャネルに送信するか閉じるかすればリクエストがキャンセルされるということのようです。

package main

import (
    "log"
    "net/http"
)

func main() {
    done := make(chan struct{})

    req, _ := http.NewRequest("GET", "http://www.google.com/", nil)
    req.Cancel = done

    go func() {
        close(done)
    }()

    _, err := http.DefaultClient.Do(req)

    log.Println(err) # Get http://www.google.com/: net/http: request canceled while waiting for connection
}

以前だとRequestをキャンセルするのに一々Client.Transportへの参照が必要だったのですが、その必要がなくなったおかげでClientのモックがやりやすくなりました。ありがたいです。

さて、このRequest.Cancelですが一つ面白い使い方があります。Go 1.5 Release Notesにもあるとおり、Request.Cancelフィールドの型はgolang.org/x/net/contextのContext.Done()の戻り値と互換性があります。つまりこのようなことができます。

package main

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

    "golang.org/x/net/context"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
    defer cancel()

    req, _ := http.NewRequest("GET", "http://www.google.com/", nil)
    req.Cancel = ctx.Done()

    _, err := http.DefaultClient.Do(req)

    log.Println(err) # Get http://www.google.com/: net/http: request canceled while waiting for connection
}

便利ですね。

ちなみに、Go1.7ではgolang.org/x/net/contextが標準パッケージに組み込まれるそうです2

10
8
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
10
8