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

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

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

问题

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

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

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

  1. type HasId interface {
  2. Id() string
  3. }
  4. func main() {
  5. client := &http.Client{
  6. Transport: &http.Transport{
  7. DialContext: wrapDialContext(&net.Dialer{}),
  8. },
  9. }
  10. trace := &httptrace.ClientTrace{
  11. GotConn: func(info httptrace.GotConnInfo) {
  12. // 这个按预期进行了转换
  13. if c, ok := (info.Conn.RemoteAddr()).(HasId); ok {
  14. fmt.Printf("info.Conn.RemoteAddr() HasId: %s\n", c.Id())
  15. }
  16. // 为什么这个没有转换?
  17. if c, ok := (info.Conn).(HasId); ok {
  18. fmt.Printf("info.Conn HasId: %s\n", c.Id())
  19. }
  20. },
  21. }
  22. req, err := http.NewRequest("GET", "https://gobyexample.com", nil)
  23. req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
  24. ...
  25. resp, err := client.Do(req)
  26. ...
  27. }
  28. func wrapDialContext(dialer *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error) {
  29. return func(ctx context.Context, network, address string) (net.Conn, error) {
  30. conn, err := dialer.DialContext(ctx, network, address)
  31. wrappedConn := TrackedConn{
  32. conn,
  33. "wrappedConn id",
  34. }
  35. return wrappedConn, err
  36. }
  37. }
  38. type wrappedAddr struct {
  39. net.Addr
  40. ident string
  41. }
  42. func (ta wrappedAddr) Id() string {
  43. return "wrappedAddr id"
  44. }
  45. type TrackedConn struct {
  46. conn net.Conn
  47. id string
  48. }
  49. func (c TrackedConn) Id() string {
  50. return "TrackedConn id"
  51. }
  52. func (c TrackedConn) RemoteAddr() net.Addr {
  53. return wrappedAddr{
  54. Addr: c.conn.RemoteAddr(),
  55. ident: c.id,
  56. }
  57. }
  58. // 其他方法来满足`net.Conn`接口。可以忽略它们。
  59. ....

执行它们的结果是

  1. 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.

  1. type HasId interface {
  2. Id() string
  3. }
  4. func main() {
  5. client := &http.Client{
  6. Transport: &http.Transport{
  7. DialContext: wrapDialContext(&net.Dialer{}),
  8. },
  9. }
  10. trace := &httptrace.ClientTrace{
  11. GotConn: func(info httptrace.GotConnInfo) {
  12. // this is cast as expected
  13. if c, ok := (info.Conn.RemoteAddr()).(HasId); ok {
  14. fmt.Printf("info.Conn.RemoteAddr() HasId: %s\n", c.Id())
  15. }
  16. // why is this not cast ?
  17. if c, ok := (info.Conn).(HasId); ok {
  18. fmt.Printf("info.Conn HasId: %s\n", c.Id())
  19. }
  20. },
  21. }
  22. req, err := http.NewRequest("GET", "https://gobyexample.com", nil)
  23. req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
  24. ...
  25. resp, err := client.Do(req)
  26. ...
  27. }
  28. func wrapDialContext(dialer *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error) {
  29. return func(ctx context.Context, network, address string) (net.Conn, error) {
  30. conn, err := dialer.DialContext(ctx, network, address)
  31. wrappedConn := TrackedConn{
  32. conn,
  33. "wrappedConn id",
  34. }
  35. return wrappedConn, err
  36. }
  37. }
  38. type wrappedAddr struct {
  39. net.Addr
  40. ident string
  41. }
  42. func (ta wrappedAddr) Id() string {
  43. return "wrappedAddr id"
  44. }
  45. type TrackedConn struct {
  46. conn net.Conn
  47. id string
  48. }
  49. func (c TrackedConn) Id() string {
  50. return "TrackedConn id"
  51. }
  52. func (c TrackedConn) RemoteAddr() net.Addr {
  53. return wrappedAddr{
  54. Addr: c.conn.RemoteAddr(),
  55. ident: c.id,
  56. }
  57. }
  58. // Other methods to fulfil `net.Conn` interface. It's ok to ignore them.
  59. ....

Executing them results in

  1. 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的类型:

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

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

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

英文:

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

  1. 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:

确定