Why my Go net.Conn is not cast to custom interface when using httpTrace.ClientTrace{GotConn}

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

Why my Go net.Conn is not cast to custom interface when using httpTrace.ClientTrace{GotConn}

问题

为了跟踪连接(在这种情况下,我想给我的连接一个名称),我用一个名为TrackedConn的结构体对其进行了封装。这个TrackedConn实现了HasId接口,并且在调用时应该返回一个标识符。

然而,当我尝试将其转换为HasId接口时,放在httptrace.ClientTrace{}的GotConn中,它是无效的。我想知道为什么会这样?

wrappedAddr只是为了向您展示它的工作原理。

type HasId interface {
	Id() string
}

func main() {
	client := &http.Client{
		Transport: &http.Transport{
			DialContext: wrapDialContext(&net.Dialer{}),
		},
	}

	trace := &httptrace.ClientTrace{
		GotConn: func(info httptrace.GotConnInfo) {

			// 这个按预期进行了转换
			if c, ok := (info.Conn.RemoteAddr()).(HasId); ok {
				fmt.Printf("info.Conn.RemoteAddr() HasId: %s\n", c.Id())
			}

			// 为什么这个没有转换?
			if c, ok := (info.Conn).(HasId); ok {
				fmt.Printf("info.Conn HasId: %s\n", c.Id())
			}
		},
	}

	req, err := http.NewRequest("GET", "https://gobyexample.com", nil)
	req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
	...
	resp, err := client.Do(req)
	...

}

func wrapDialContext(dialer *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error) {
	return func(ctx context.Context, network, address string) (net.Conn, error) {
		conn, err := dialer.DialContext(ctx, network, address)
		wrappedConn := TrackedConn{
			conn,
			"wrappedConn id",
		}
		return wrappedConn, err
	}
}

type wrappedAddr struct {
	net.Addr
	ident string
}

func (ta wrappedAddr) Id() string {
	return "wrappedAddr id"
}

type TrackedConn struct {
	conn net.Conn
	id   string
}

func (c TrackedConn) Id() string {
	return "TrackedConn id"
}

func (c TrackedConn) RemoteAddr() net.Addr {
	return wrappedAddr{
		Addr:  c.conn.RemoteAddr(),
		ident: c.id,
	}
}

// 其他方法来满足`net.Conn`接口。可以忽略它们。
....

执行它们的结果是

info.Conn.RemoteAddr() HasId: wrappedAddr id

我期望也能看到info.Conn HasId: wrappedConn id

完整代码在这里:https://play.golang.org/p/05qx45Ub8DH(由于HTTP请求的原因,Playground将无法工作)

英文:

To track connection (in this case, I want to give my connection a name), I wrapped it with a struct TrackedConn. This TrackedConn implements HasId interface and it's expected to return an identifier when call.

However, when I try to cast it to HasId interface inside httptrace.ClientTrace{} GotConn, it wasn't valid. I wonder why is that ?

wrappedAddr is just to show you that it works.

type HasId interface {
	Id() string
}

func main() {
	client := &http.Client{
		Transport: &http.Transport{
			DialContext: wrapDialContext(&net.Dialer{}),
		},
	}

	trace := &httptrace.ClientTrace{
		GotConn: func(info httptrace.GotConnInfo) {

			// this is cast as expected
			if c, ok := (info.Conn.RemoteAddr()).(HasId); ok {
				fmt.Printf("info.Conn.RemoteAddr() HasId: %s\n", c.Id())
			}

			// why is this not cast ?
			if c, ok := (info.Conn).(HasId); ok {
				fmt.Printf("info.Conn HasId: %s\n", c.Id())
			}
		},
	}

	req, err := http.NewRequest("GET", "https://gobyexample.com", nil)
	req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
	...
	resp, err := client.Do(req)
	...

}

func wrapDialContext(dialer *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error) {
	return func(ctx context.Context, network, address string) (net.Conn, error) {
		conn, err := dialer.DialContext(ctx, network, address)
		wrappedConn := TrackedConn{
			conn,
			"wrappedConn id",
		}
		return wrappedConn, err
	}
}

type wrappedAddr struct {
	net.Addr
	ident string
}

func (ta wrappedAddr) Id() string {
	return "wrappedAddr id"
}

type TrackedConn struct {
	conn net.Conn
	id   string
}

func (c TrackedConn) Id() string {
	return "TrackedConn id"
}

func (c TrackedConn) RemoteAddr() net.Addr {
	return wrappedAddr{
		Addr:  c.conn.RemoteAddr(),
		ident: c.id,
	}
}

// Other methods to fulfil `net.Conn` interface. It's ok to ignore them.
....


Executing them results in

info.Conn.RemoteAddr() HasId: wrappedAddr id

I expected to see info.Conn HasId: wrappedConn id" as well

Full code here : https://play.golang.org/p/05qx45Ub8DH
(Playground is not going to work because of HTTP request)

答案1

得分: 2

为了调试您的问题,请查看info.Conn的类型:

fmt.Printf("conn type: %T", info.Conn)

您正在联系一个https服务器,所以您得到的类型是:*tls.Conn

您需要插入到您的Transport.DialTLSContext()方法中。

英文:

To debug your issue, look at the type of info.Conn :

fmt.Printf("conn type: %T", info.Conn)

You are contacting an https server, so the type you get is : *tls.Conn.

You need to plug into your Transport.DialTLSContext() method.

huangapple
  • 本文由 发表于 2021年10月5日 21:09:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/69451093.html
匿名

发表评论

匿名网友

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

确定