• Golang net/http 包中的 RoundTripper 接口详解


    目录

    RoundTripper 是什么? 

    使用场景

    RoundTripper 的最佳实践

    小结


    RoundTripper 是什么? 

    RoundTripper 是 net/http 包中的一个接口,定义了处理 HTTP 请求返回和响应的方法,是 http.Client 结构体中执行 http 请求的核心部分。接口定义如下:

    1. type RoundTripper interface {
    2. RoundTrip(*Request) (*Response, error)
    3. }

    只定义了 RoundTrip 一个方法,用于执行单个 HTTP 事务,发送请求数据并返回对应的响应数据。RoundTrip 不应该去解析响应数据,特别是如果获得了响应数据后,RoundTrip 必须返回值为 nil 的 error(不管响应的HTTP状态码是什么)。如果没有获得响数据,应返回一个非 nil 的 error,RoundTrip 也不应该尝试处理更高级的协议细节,如重定向、身份验证或 cookie 等。

    除了消费和关闭请求的 Body 之外,RoundTrip 不应该修改请求,RoundTrip 可以在单独的 goroutine 中读取请求的字段。在 Response Body 被关闭之前,调用方不应该改变或重用请求。RoundTrip 必须始终关闭 body(即使遇到 error),但根据实现,即使在 RoundTrip 返回之后也可以在单独的 goroutine 中关闭。

    使用场景

    借助 RoundTripper 可以在每个请求中添加特定的 header 或者对返回的响应数据进行特定的处理,例如记录日志或根据返回的状态码执行对应逻辑。接下来看一个用于实现链路追踪功能,只需要实现 RoundTripper 接口,在执行 HTTP 请求的同时,收集遥测数据,如请求的持续时间、状态码等,这些数据可以用于性能监控和故障排查。实现 RoundTripper 接口的示例代码如下:

    1. package http_otel
    2. import (
    3. "net/http"
    4. "go.opentelemetry.io/otel"
    5. "go.opentelemetry.io/otel/attribute"
    6. "go.opentelemetry.io/otel/codes"
    7. )
    8. type OtelRoundTripper struct {
    9. original http.RoundTripper
    10. }
    11. func (ort *OtelRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
    12. tracer := otel.Tracer("")
    13. ctx, span := tracer.Start(req.Context(), req.URL.Path)
    14. defer span.End()
    15. req = req.WithContext(ctx)
    16. resp, err := ort.original.RoundTrip(req)
    17. if err != nil {
    18. span.RecordError(err)
    19. span.SetStatus(codes.Error, err.Error())
    20. } else {
    21. attrs := []attribute.KeyValue{
    22. {
    23. Key: "http.status_code",
    24. Value: attribute.IntValue(resp.StatusCode),
    25. },
    26. {
    27. Key: "http.method",
    28. Value: attribute.StringValue(req.Method),
    29. },
    30. {
    31. Key: "http.route",
    32. Value: attribute.StringValue(req.URL.RequestURI()),
    33. },
    34. {
    35. Key: "http.scheme",
    36. Value: attribute.StringValue(req.URL.Scheme),
    37. },
    38. {
    39. Key: "http.user_agent",
    40. Value: attribute.StringValue(req.UserAgent()),
    41. },
    42. }
    43. span.SetAttributes(attrs...)
    44. }
    45. return resp, err
    46. }
    47. func New(tripper http.RoundTripper) *OtelRoundTripper {
    48. return &OtelRoundTripper{
    49. original: tripper,
    50. }
    51. }

    使用 net/http 包实现链路追踪代码如下:

    1. package main
    2. import (
    3. "bytes"
    4. "fmt"
    5. "xxx/http-otel"
    6. "io"
    7. "net/http"
    8. )
    9. func main() {
    10. reader := bytes.NewReader([]byte(`{"foo":"bar"}`))
    11. request, err := http.NewRequest("POST", "http://xxx.com/user/list", reader)
    12. if err != nil {
    13. panic(err)
    14. }
    15. request = request.WithContext(traceCtx) // traceCtx 指上文的 context,这里使用伪代码作演示
    16. request.Header.Set("Content-Type", "application/json")
    17. client := http.Client{Transport: http_otel.New(http.DefaultTransport)}
    18. resp, err := client.Do(request)
    19. if err != nil {
    20. panic(err)
    21. }
    22. defer resp.Body.Close()
    23. b, err := io.ReadAll(resp.Body)
    24. fmt.Println(string(b), err)
    25. }

    首先定义了一个用于实现链路追踪功能的 OtelRoundTripper 结构体,然后实现了 RoundTrip 方法。在 RoundTrip 方法中,首先开启一个新的 trace span,并且将追踪的信息编码到 HTTP 请求的 header 中。在请求完成后,将返回的 HTTP 响应信息记录到 trace 中,并返回 HTTP 响应数据。

    RoundTripper 的最佳实践

     在实现自定义 RoundTripper 时,应该遵守一些最佳实践:

    • 避免在 RoundTrip 方法中进行不必要的内存分配,这会增加垃圾收集器的压力并降低性能。
    • 应该确保 RoundTripper 的实现不会造成内存泄露,例如未关闭的网络连接。
    • RoundTripper 的实现对于客户端的性能至关重要。一个高效的 RoundTripper 可以通过合理的连接复用和缓存策略来减少延迟和带宽的使用,从而提高整体的性能。

    • 需要注意安全性,例如,如果 RoundTripper 需要处理敏感信息,需要确保在整个过程中使用适当的加密和验证措施。

    小结

    RoundTripper 接口的强大之处在于能够以简单且可扩展的方式自定义和控制 HTTP 请求的处理。无论是添加特定的 header、处理响应还是执行其他更高级的逻辑,都可以借助 RoundTripper 来实现。

  • 相关阅读:
    JAVA毕业设计102—基于Java+Springboot+vue的个人理财管理系统(源码+数据库)
    双链笔记葫芦笔记综合评测:优点、缺点、建议
    windows系统安装ubuntu22.04虚拟机
    【java学习】数组中涉及的常见算法-含冒泡排序(11)
    Qt 线程串口
    编译原理实验-词法分析
    FPGA信号处理系列文章——码元同步
    SpringBoot中任务是什么/Quartz和SpringTask在Spring Boot中怎么使用/SpringBoot怎么给用户发邮件
    常坐飞机的你,为什么老惦记着“升舱”?
    Spring Boot + Activiti 完美结合,快速实现工作流~
  • 原文地址:https://blog.csdn.net/luduoyuan/article/details/133149423