英文:
Replace TLSClientConfig inside the transport of an http.Client?
问题
请考虑以下问题。
ourClient
是一个 *http.Client
类型的变量 - 一旦生成,如何单独更改该 http.Client 的 TLSClientConfig
(类型为 tls.Config{}
)?
package main
import (
"crypto/tls"
"fmt"
"net"
"net/http"
"time"
)
func main() {
transport := &http.Transport{
TLSHandshakeTimeout: 10 * time.Second,
Dial: (&net.Dialer{
Timeout: 1 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSClientConfig: &tls.Config{},
}
ourClient := &http.Client{
Timeout: 5 * time.Second,
Transport: transport,
}
fmt.Printf("http.Client Timeout %v\n", ourClient.Timeout)
ourClient.Timeout = 3 * time.Second
fmt.Printf("http.Client Timeout %v\n", ourClient.Timeout)
// 如何替换 ourClient 中的 TLSClientConfig
newTLSClientConfig := &tls.Config{}
transport.TLSClientConfig = newTLSClientConfig
fmt.Printf("http: %#v\n", ourClient)
}
(也可在 https://go.dev/play/p/v1HJLZ-MhhH 上查看)
英文:
Please consider this question.
ourClient
is an *http.Client
- once it is generated, how can TLSClientConfig
(which is of type tls.Config{}
) alone be changed of this http.Client?
package main
import (
"crypto/tls"
"fmt"
"net"
"net/http"
"time"
)
func main() {
transport := &http.Transport{
TLSHandshakeTimeout: 10 * time.Second,
Dial: (&net.Dialer{
Timeout: 1 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSClientConfig: &tls.Config{},
}
ourClient := &http.Client{
Timeout: 5 * time.Second,
Transport: transport,
}
fmt.Printf("http.Client Timeout %v\n", ourClient.Timeout)
ourClient.Timeout = 3 * time.Second
fmt.Printf("http.Client Timeout %v\n", ourClient.Timeout)
// how do I replace the TLSClientConfig in ourClient
// newTLSClientConfig := &tls.Config{}
// ourClient.Transport.TLSClientConfig = newTLSClientConfig
// ourClient.Transport.TLSClientConfig undefined (type http.RoundTripper has no field or method TLSClientConfig)
fmt.Printf("http: %#v\n", ourClient)
}
(Also posted as https://go.dev/play/p/v1HJLZ-MhhH)
答案1
得分: 1
http.RoundTripper
是一个接口 - 你需要使用 类型断言 将其转换为具体的实现,例如:
...
newTLSClientConfig := &tls.Config{}
if tpt, ok := ourClient.Transport.(*http.Transport); ok {
tpt.TLSClientConfig = newTLSClientConfig
}
...
https://go.dev/play/p/2UinL3Uazid
这个链接可能更好地解释了这个问题 here,但是值得一提的是 - http.Client.Transport 被声明为一个 RoundTripper 接口,一个接口可以有许多不同的实现,并且没有一个实现被 接口 合约保证具有 TLSClientConfig
字段。因此,Go 编译器不允许你赋值 newTLSClientConfig
字段 - 因为它在法律上不能这样做。
类型断言 断言接口的具体实现符合类型,并将接口的实现(在这种情况下是 http.Transport
)赋值给变量(在这种情况下是 tpt
)。因此,tpt
现在保证是 http.Transport
的一个实例,这意味着你现在可以将 newTLSClientConfig
赋值给 TLSClientConfig
字段。
如果 ok
为 false,这意味着 RoundTripper
接口的实现不是 http.Transport
。
英文:
http.RoundTripper
is an interface - you need to convert it to the concrete implementation using a type assertion, e.g.:
...
newTLSClientConfig := &tls.Config{}
if tpt, ok := ourClient.Transport.(*http.Transport); ok {
tpt.TLSClientConfig = newTLSClientConfig
}
...
https://go.dev/play/p/2UinL3Uazid
It's probably better explained here, but FWIW - http.Client.Transport is declared as a RoundTripper interface and an interface can have many different implementations and none of them are guaranteed by the interface contract to have a TLSClientConfig
field. So the Go compiler won't let you assign newTLSClientConfig
field - because it legally can't.
A type assertion asserts that the concrete implementation of the interface conforms to the type and also assigns the implementation of the interface (http.Transport
in this case) to the variable (tpt
in this case). So tpt
is now guaranteed to be an instance of http.Transport
which means you can now assign newTLSClientConfig
to the TLSClientConfig
field.
If ok
had been false it would have meant that the implementation of the RoundTripper
interface was not an http.Transport
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论