替换http.Client中传输的TLSClientConfig?

huangapple go评论179阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2022年11月6日 08:52:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/74332573.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定