在不修改 Client.Transport 的情况下切换 Go HTTP 代理路由
使用同步的 RoundTripper 包装器发布新的已配置代理传输,而不修改正在运行的 http.Client 字段。
如果某个 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。如果整个工作流需要同一条路由,请在工作流边界处指定该路由,而不是中途更换这个共享选择器。