LoginSignup
38
36

More than 5 years have passed since last update.

GoでlocalhostのWebサーバーに本番用のホスト名でHTTPリクエストする

Last updated at Posted at 2015-06-10

こんにちは、@ono_matopeです。

GoでHTTPサーバを開発する際、通常はlocalhostで適当にサーバを起動し、

resp, err := client.Get("http://localhost:8080/hello")

など、ホスト名にローカルアドレスを指定したHTTPリクエストを発行してテストをしていることと思います。(net/http/httptestを使った場合も基本的には同じ)

ですが、例えば http://matope.github.com のように、URLホスト名の一部がパラメータであるなどの理由によって、localhost以外のホスト名でHTTPサーバをテストしなければいけないことがあります。こんな時にどうしてますか?hosts? dnsmasq? つらいですね。

実はGoであれば、ほんの少しのコード追加で、ローカルのサーバーに任意のホスト名でHTTPリクエストを発行することができます。

    new_addr := "localhost:8080"

    var localDial = func(network, addr string) (net.Conn, error) {
        return http.DefaultTransport.(*http.Transport).Dial(network, new_addr)
    }

    var localDialTLS = func(network, addr string) (net.Conn, error) {
        return http.DefaultTransport.(*http.Transport).DialTLS(network, new_addr)
    }

    client := &http.Client{
        Transport: &http.Transport{
            Dial:    localDial,    //replace Dial
            DialTLS: localDialTLS, //replace DialTLS
        },
    }

    resp, err := client.Get("http://username.example.com/hello")

ご覧の通り、http.Transport構造体のDial(とDialTLS)関数を書き換え、HTTPリクエストによるDialをすべてlocalhost:8080に上書きしています。これにより、HTTPレベルでは

GET /hello HTTP/1.1
Host: username.example.com

と、本番用のホスト名でありながら、TCPレベルではlocalhostにリクエストを発行することに成功します。両レイヤーが綺麗に分離されたGoの標準ライブラリは本当に素晴らしいです。
これでかっこいいサブドメインのテストもhosts不要でらくちんですね。

(note: 上の例ではDial関数本体はhttp.DefaultTransport.Dial関数を使っていますが、これではDefaultTransportのDial関数をlocalDialに変更した場合、たぶん無限再帰呼び出しになってしまうので、下の方がいいかもしれません)

    var localDial = func(network, addr string) (net.Conn, error) {
        return (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).Dial(network, "localhost:8080")
    }
38
36
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
38
36