详解Golang net/http包中的RoundTripper接口
作者:路多辛
RoundTripper 是什么?
RoundTripper 是 net/http 包中的一个接口,定义了处理 HTTP 请求返回和响应的方法,是 http.Client 结构体中执行 http 请求的核心部分。接口定义如下:
type RoundTripper interface { RoundTrip(*Request) (*Response, error) }
只定义了 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 接口的示例代码如下:
package http_otel import ( "net/http" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" ) type OtelRoundTripper struct { original http.RoundTripper } func (ort *OtelRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { tracer := otel.Tracer("") ctx, span := tracer.Start(req.Context(), req.URL.Path) defer span.End() req = req.WithContext(ctx) resp, err := ort.original.RoundTrip(req) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) } else { attrs := []attribute.KeyValue{ { Key: "http.status_code", Value: attribute.IntValue(resp.StatusCode), }, { Key: "http.method", Value: attribute.StringValue(req.Method), }, { Key: "http.route", Value: attribute.StringValue(req.URL.RequestURI()), }, { Key: "http.scheme", Value: attribute.StringValue(req.URL.Scheme), }, { Key: "http.user_agent", Value: attribute.StringValue(req.UserAgent()), }, } span.SetAttributes(attrs...) } return resp, err } func New() *OtelRoundTripper { return &OtelRoundTripper{ original: tripper, } }
使用 net/http 包实现链路追踪代码如下:
package main import ( "bytes" "fmt" "xxx/http-otel" "io" "net/http" ) func main() { reader := bytes.NewReader([]byte(`{"foo":"bar"}`)) request, err := http.NewRequest("POST", "http://xxx.com/user/list", reader) if err != nil { panic(err) } request = request.WithContext(traceCtx) // traceCtx 指上文的 context,这里使用伪代码作演示 request.Header.Set("Content-Type", "application/json") client := http.Client{Transport: http_otel.New()} resp, err := client.Do(request) if err != nil { panic(err) } defer resp.Body.Close() b, err := io.ReadAll(resp.Body) fmt.Println(string(b), err) }
首先定义了一个用于实现链路追踪功能的 OtelRoundTripper 结构体,然后实现了 RoundTrip 方法。在 RoundTrip 方法中,首先开启一个新的 trace span,并且将追踪的信息编码到 HTTP 请求的 header 中。在请求完成后,将返回的 HTTP 响应信息记录到 trace 中,并返回 HTTP 响应数据。
小结
RoundTripper 接口的强大之处在于能够以简单且可扩展的方式自定义和控制 HTTP 请求的处理。无论是添加特定的 header、处理响应还是执行其他更高级的逻辑,都可以借助 RoundTripper 来实现。
以上就是详解Golang net/http包中的RoundTripper接口的详细内容,更多关于Golang RoundTripper接口的资料请关注脚本之家其它相关文章!