6

I am trying to control keep-alives session to reuse the tcp connection by creating a Trasport.

Here is my snippet and I am not sure how to add headers info for authentication.

url := "http://localhost:8181/api/v1/resource"
tr := &http.Transport{
    DisableKeepAlives:   false,
    MaxIdleConns:        0,
    MaxIdleConnsPerHost: 0,
    IdleConnTimeout:     time.Second * 10,
}
client := &http.Client{Transport: tr}
resp, err := client.Get(url)
James Sapam
  • 16,036
  • 12
  • 50
  • 73
  • You don't. The Headers are taken from the `*http.Request`. The default for DisableKeepAlives is false, which means connections will be reused whenever possible . – JimB Dec 19 '16 at 19:34
  • So, looks like i don't need to create Transport as its `DisableKeepAlives` is false by default. – James Sapam Dec 19 '16 at 19:40
  • Also, If you're going to override the `DefaultTransport`, you should still make sure you copy all the important settings, i.e. you almost always want a DialContext with a Timeout. (and your first 3 fields are the zero value, so setting those doesn't do anything) – JimB Dec 19 '16 at 19:40
  • @JimB tried using go-routine but the number of TCP connection is piling up. – James Sapam Dec 19 '16 at 20:19
  • What are you using a goroutine for? You should have a single Transport, probably the DefaultTransport, regardless of any goroutines. – JimB Dec 19 '16 at 20:25
  • I am trying to do parallel get request from a pool of worker. – James Sapam Dec 19 '16 at 21:43
  • Here is the snippet i am trying: https://play.golang.org/p/O2nYhbhgyI it creates lots of tcp session. – James Sapam Dec 19 '16 at 22:10

3 Answers3

8

This may not be what you want for your specific question - setting it in the request makes more sense in your case, but to answer your question directly, you should be able to add a default header to all the requests going through the transport by using a custom RoundTrip method for your Transport.

Check out https://golang.org/pkg/net/http/#RoundTripper

Something like :

type CustomTransport struct {
  http.RoundTripper
}

func (ct *CustomTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    req.Header.Add("header-key", "header-value")
    return ct.RoundTripper.RoundTrip(req)
}

url := "http://localhost:8181/api/v1/resource"
tr := &CustomTransport{
    DisableKeepAlives:   false,
    MaxIdleConns:        0,
    MaxIdleConnsPerHost: 0,
    IdleConnTimeout:     time.Second * 10,
}
client := &http.Client{Transport: tr}
resp, err := client.Get(url)

I found this useful when I didn't have direct access to the http Client used by an API client library (or each request object directly), but it allowed me to pass in a transport.

Rakesh
  • 3,370
  • 2
  • 23
  • 41
  • Can't modify the request in your RoundTripper "// RoundTrip should not modify the request" https://pkg.go.dev/net/http#RoundTripper – Zaphod Jan 28 '22 at 02:52
3

Don't mix the Client from the Request.
The client uses a Transport and run the request: client.Do(req)

You set header on the http.Request with (h Header) Set(key, value string):

req.Header.Set("name", "value")
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Ok let me try. So, how should i do if i want to customize the transport struct. – James Sapam Dec 19 '16 at 19:41
  • @James What you are already doing. The headers though are set on the request. – VonC Dec 19 '16 at 19:41
  • Here, I am trying to use by multiple goroutine. So, thought of creating only once and reuse it. – James Sapam Dec 19 '16 at 19:44
  • @James: yes, you _should_ only use 1 Transport, but that still has nothing to do with setting the headers in each Request. – JimB Dec 19 '16 at 19:46
  • @James What headers do you want to set? Depending on your protocol, you might need them only on the first write, like in grpc: https://github.com/grpc/grpc-go/blob/8712952b7d646dbbbc6fb73a782174f3115060f3/transport/handler_server.go#L218-L241 – VonC Dec 19 '16 at 19:47
0

This is what I found:

    package main

    import (
        "fmt"
        "io/ioutil"
        "net/http"
    )

    var URL = "http://httpbin.org/ip"

    func main() {
        tr := &http.Transport{DisableKeepAlives: false}
        req, _ := http.NewRequest("GET", URL, nil)
        req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", "Token"))
        req.Close = false

        res, err := tr.RoundTrip(req)
        if err != nil {
            fmt.Println(err)
        }
        body, _ := ioutil.ReadAll(res.Body)
        fmt.Println(string(body))
    }

And it works.

James Sapam
  • 16,036
  • 12
  • 50
  • 73