I\'m making a URL fetcher in Go and have a list of URLs to fetch. I send http.Get()
requests to each URL and obtain their response.
resp,fetch_e
Apparently in Go 1.3 http.Client has Timeout field
client := http.Client{
Timeout: 5 * time.Second,
}
client.Get(url)
That's done the trick for me.
You may use https://github.com/franela/goreq which handles timeouts in a fashion and simple way.
A quick and dirty way:
http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 45
This is mutating global state w/o any coordination. Yet it might be possibly okay for your url fetcher. Otherwise create a private instance of http.RoundTripper
:
var myTransport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
ResponseHeaderTimeout: time.Second * 45,
}
var myClient = &http.Client{Transport: myTransport}
resp, err := myClient.Get(url)
...
Nothing above was tested.
timeout := time.Duration(5 * time.Second)
transport := &http.Transport{Proxy: http.ProxyURL(proxyUrl), ResponseHeaderTimeout:timeout}
This may help, but notice that ResponseHeaderTimeout
starts only after the connection is established.
To add to Volker's answer, if you would also like to set the read/write timeout in addition to the connect timeout you can do something like the following
package httpclient
import (
"net"
"net/http"
"time"
)
func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
return func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, cTimeout)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(rwTimeout))
return conn, nil
}
}
func NewTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client {
return &http.Client{
Transport: &http.Transport{
Dial: TimeoutDialer(connectTimeout, readWriteTimeout),
},
}
}
This code is tested and is working in production. The full gist with tests is available here https://gist.github.com/dmichael/5710968
Be aware that you will need to create a new client for each request because of the conn.SetDeadline
which references a point in the future from time.Now()
You need to set up your own Client with your own Transport which uses a custom Dial function which wraps around DialTimeout.
Something like (completely untested) this:
var timeout = time.Duration(2 * time.Second)
func dialTimeout(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, timeout)
}
func main() {
transport := http.Transport{
Dial: dialTimeout,
}
client := http.Client{
Transport: &transport,
}
resp, err := client.Get("http://some.url")
}