Defaults and limits¶
Every value NewClient() and NewTransport() set when you pass no options, and every
setting they deliberately leave alone. The options that change them are documented in
client options.
What NewClient sets on the *http.Client¶
| Field | Value | Changed by |
|---|---|---|
Timeout |
30s | WithTimeout |
Transport |
the transport from NewTransport, wrapped by retry and the middleware chain when configured |
WithTransport, WithRetry, WithClientMiddleware |
CheckRedirect |
policy capping the chain at 10 requests, refusing an HTTPS→HTTP downgrade, and stripping named sensitive headers cross-origin | WithMaxRedirects, WithSensitiveHeaders |
Jar |
not set — the client stores no cookies | nothing; assign one yourself |
Each call to NewClient builds its own transport and therefore its own connection pool.
Build one client per downstream service and reuse it; a client created per request gets no
connection reuse and leaks idle connections until they time out.
What NewTransport sets on the *http.Transport¶
| Field | Value | Bounds |
|---|---|---|
Proxy |
http.ProxyFromEnvironment |
proxy selection from the environment |
TLSClientConfig |
DefaultConfig() from go/tls, or the config you pass |
see TLS settings |
MaxIdleConns |
100 | idle connections kept across all hosts |
MaxIdleConnsPerHost |
10 | idle connections kept per host |
IdleConnTimeout |
90s | how long an idle connection is kept before closing |
TLSHandshakeTimeout |
10s | handshake must complete within this |
ExpectContinueTimeout |
1s | wait for a 100 Continue after an Expect header |
ResponseHeaderTimeout |
30s | time from finishing the request to the first response byte |
DialContext |
net.Dialer{Timeout: 30s, KeepAlive: 30s} |
TCP connect timeout and keep-alive interval |
ResponseHeaderTimeout is the one to reach for when a downstream hangs after accepting the
request: it fails the attempt without waiting for the whole 30-second client timeout, and
it does not cover the response body, so a slow large download is not cut short by it.
There is no option that changes an individual transport field. Build a transport with
NewTransport, adjust the field, and pass it to WithTransport.
Which transport settings are left at Go's zero value¶
These are not configured, so the standard library's behaviour applies unchanged. They are listed because "is there a limit on X?" is usually answered here.
| Field | Zero value means |
|---|---|
MaxConnsPerHost |
unlimited total connections per host — only idle connections are capped |
ForceAttemptHTTP2 |
HTTP/2 is not attempted; see HTTP/2 is not negotiated |
DisableKeepAlives |
keep-alives are on |
DisableCompression |
Accept-Encoding: gzip is added and responses are transparently decompressed |
MaxResponseHeaderBytes |
Go's conservative default of 10 MiB of response headers |
ReadBufferSize / WriteBufferSize |
Go's 4 KiB buffers |
TLSNextProto |
left nil, so nothing blocks HTTP/2 from being wired up — but nothing wires it up either, because a custom DialContext and TLSClientConfig are set and ForceAttemptHTTP2 is false |
Nothing here bounds the size of a response body. A hostile or broken server can stream
until the client timeout expires; wrap the body in an io.LimitReader if that matters.
The TLS settings that come from go/tls¶
DefaultConfig() in go/tls supplies:
| Setting | Value |
|---|---|
MinVersion |
TLS 1.2 |
MaxVersion |
not set — TLS 1.3 is used when the server offers it |
CipherSuites |
ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, ECDHE_RSA_WITH_AES_256_GCM_SHA384, ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ECDHE_RSA_WITH_AES_128_GCM_SHA256, ECDHE_ECDSA_WITH_CHACHA20_POLY1305, ECDHE_RSA_WITH_CHACHA20_POLY1305 |
CurvePreferences |
X25519, P-256 |
RootCAs |
not set — the host's system trust store |
InsecureSkipVerify |
false; certificate verification is always on |
The cipher-suite list applies to TLS 1.0–1.2 only. TLS 1.3 cipher suites are not configurable in Go, so a TLS 1.3 connection uses Go's own suites regardless of this list.
Which environment variables the client reads¶
Only the standard proxy variables, and only because NewTransport sets
Proxy: http.ProxyFromEnvironment:
| Variable | Effect |
|---|---|
HTTP_PROXY / http_proxy |
proxy for http:// requests |
HTTPS_PROXY / https_proxy |
proxy for https:// requests |
NO_PROXY / no_proxy |
comma-separated hosts, domains or CIDRs to reach directly |
The value may be a full URL or a host:port, in which case http is assumed. Requests to
localhost or a loopback address never use a proxy. net/http reads these variables once
per process and caches the result, so changing them after the first request has no effect.
WithTransport replaces the transport and therefore drops proxy support unless the
transport you supply sets Proxy itself.
This module reads no other environment variables, and it has no configuration file and no configuration keys. Everything else is a code option.
What DefaultRetryConfig gives you¶
transithttp.DefaultRetryConfig() from
go/transit, passed to WithRetry:
| Field | Default | Notes |
|---|---|---|
MaxRetries |
3 | four attempts in total |
InitialBackoff |
500ms | first backoff, before jitter |
MaxBackoff |
30s | caps the backoff and any Retry-After |
RetryableStatusCodes |
429, 502, 503, 504 | a nil slice adopts this list; an empty slice means network errors only |
RetryAllMethods |
false | only GET, HEAD, OPTIONS, PUT and DELETE are retried |
RetryableMethods |
nil | overrides the idempotent set when supplied |
ShouldRetry |
nil | replaces the built-in decision entirely when supplied |
The delay is full jitter — a uniform random draw between zero and the exponential bound —
so backoff is an upper limit, not a fixed wait. A Retry-After header takes precedence and
is clamped to MaxBackoff.
Retry is off unless WithRetry is passed. Note that the total wall-clock cost of a
retrying request can exceed the 30-second default client timeout; see
WithTimeout.
What DefaultCircuitBreakerConfig gives you¶
transithttp.DefaultCircuitBreakerConfig(), for use inside a ClientChain:
| Field | Default | Notes |
|---|---|---|
FailureThreshold |
5 | consecutive failures that trip the breaker open |
Cooldown |
30s | how long it stays open before a trial request |
HalfOpenMaxRequests |
1 | trial requests allowed; the first success closes it |
IsFailure |
nil | defaults to transport errors and status ≥ 500 |
A 429 does not count as a failure — rate limiting is retry's concern, not a signal that
the downstream is unhealthy. While the breaker is open, calls fail immediately with
transithttp.ErrCircuitOpen, testable with errors.Is.
WithRateLimit(rps) in the same chain is a token bucket with a burst of 1, shared by every
request through that transport; it blocks until a token is free or the request context is
cancelled.