こんにちは、@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")
}