英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论