如果某个 http.Client 已被并发请求共享,请保持其 Transport 字段稳定。包装器可以同步后续每次往返所收到的、已完整配置的传输:

type routeSlot struct {
    mu sync.RWMutex
    current http.RoundTripper
}

func (s *routeSlot) RoundTrip(r *http.Request) (*http.Response, error) {
    s.mu.RLock()
    current := s.current
    s.mu.RUnlock()
    return current.RoundTrip(r)
}

func (s *routeSlot) Set(next http.RoundTripper) {
    s.mu.Lock()
    s.current = next
    s.mu.Unlock()
}

使用 net/http 和 sync,在发布客户端之前完成初始化:

slot := &routeSlot{current: initialTransport}
client := &http.Client{Transport: slot}

slot.Set(nextTransport)

initialTransport 和 nextTransport 必须非 nil、配置完整且并发安全。每次发布代理传输之前先构建它,并在请求使用期间保持其配置不变。

锁只保护指针快照,因此慢请求不会在整个网络交换期间一直持有路由锁。已经使用上一份快照的请求会继续在该传输上执行;切换不会重放该请求,也不会移动其连接。

请通过应用程序有界的生命周期保留并淘汰旧传输,允许进行中的工作完成,并在合适时关闭空闲连接池。重定向可能在切换之后引发另一次 RoundTrip。如果整个工作流需要同一条路由,请在工作流边界处指定该路由,而不是中途更换这个共享选择器。

相关文章