OkHttp & Interceptors Quiz

DATA › Networking

Which interceptor type is guaranteed to be invoked exactly once per call, even when OkHttp follows redirects or serves the response from cache?

Answer: Application interceptor (addInterceptor)

Application interceptors run once per logical call regardless of redirects, retries, or cache hits. Network interceptors run once per actual network request, so they can fire multiple times or not at all (cache hit).

You add a network interceptor that logs Accept-Encoding. Why might it show 'gzip' even though your code never set that header?

Answer: OkHttp adds Accept-Encoding: gzip, and network interceptors see it

When you do not set Accept-Encoding yourself, OkHttp adds gzip transparently. Network interceptors observe the request after OkHttp's own headers are added, so they see it; application interceptors do not.

What is the correct way to add an Authorization header to every outgoing request in OkHttp?

Answer: Copy via newBuilder().header(...) and call chain.proceed()

Request is immutable, so you create a modified copy with newBuilder() and proceed with it. There is no in-place mutation and no client subclassing involved.

Which configuration is the appropriate place to enforce certificate pinning, and on which client object?

Answer: A CertificatePinner set on OkHttpClient.Builder

Pinning is configured with CertificatePinner on OkHttpClient.Builder().certificatePinner(...). It validates the server's certificate chain against expected SHA-256 public-key hashes during the TLS handshake.

Your app shares a single OkHttpClient instance across the whole process. What is the main benefit?

Answer: It reuses the connection pool, thread pools, and cache

OkHttpClient holds the ConnectionPool, dispatcher thread pools, and cache. Sharing one instance lets keep-alive connections and threads be reused instead of recreated per request.

callTimeout is set to 0 (the default) while connectTimeout, readTimeout, and writeTimeout are each 10 seconds. What does this mean for a request that follows two redirects?

Answer: No total cap; each connect/read/write phase on each hop still has 10s.

callTimeout = 0 means no limit on total call duration (including redirects, retries, and body). The per-phase connect/read/write timeouts still apply independently to each network operation.

Which statement about OkHttp's application interceptors is FALSE?

Answer: They have direct access to the underlying Connection for TLS/IP inspection

Access to the Connection (chain.connection(), for IP/TLS inspection) is available to network interceptors, not application interceptors. The other three statements are true of application interceptors.

Your API returns 401 when an access token has expired, and you want OkHttp to transparently obtain a fresh token and retry the original request. Which mechanism is purpose-built for this?

Answer: OkHttp's Authenticator via authenticator(), which retries on 401

Authenticator is called reactively after the server responds 401 (or 407 for proxies); it returns a new Request to retry or null to give up, and inspecting the prior Authorization header lets you avoid infinite refresh loops.

You register addInterceptor(A) and then addInterceptor(B) on the same client. In what order do they process an outgoing request and its response?

Answer: A sees the request before B, and B sees the response before A.

Interceptors form an ordered chain in registration order: the request flows A then B outward via chain.proceed(), and the response unwinds B then A. Application interceptors always sit above the network interceptors and the network code.

Inside an application interceptor you call response.body().string() to inspect the payload, then return that same response object to the caller. What happens at the call site?

Answer: The caller gets an empty or closed body; the stream was consumed

A ResponseBody is a one-shot stream that string() fully consumes and closes. To inspect and still forward it, use peekBody() or rebuild the Response with a fresh ResponseBody created from the bytes you read.

Why should HttpLoggingInterceptor.Level.BODY not be left enabled in a release build?

Answer: It logs full headers and bodies to Logcat, leaking tokens and PII

BODY level writes headers and full bodies to Logcat, exposing bearer tokens and user data on a device's logs. Restrict it to debug builds and call redactHeader() for any sensitive header you must keep.

With a Cache configured, you want stored responses served when the device is offline even though the server's Cache-Control marks them stale. What is the idiomatic OkHttp approach?

Answer: Add an interceptor setting Cache-Control: max-stale when offline

An interceptor can rewrite the request Cache-Control (e.g. CacheControl.FORCE_CACHE or only-if-cached with max-stale) when offline, so OkHttp returns a stored response instead of failing; online you let normal validation proceed.

OkHttp's Dispatcher caps how many asynchronous (enqueue) calls run at once. Which settings control that concurrency?

Answer: Dispatcher.maxRequests and Dispatcher.maxRequestsPerHost

maxRequests (default 64) caps total in-flight async calls and maxRequestsPerHost (default 5) caps per-host concurrency. The ConnectionPool governs idle keep-alive connections, which is a separate concern from dispatch concurrency.

OkHttp transparently decompresses gzipped responses, but to send a gzip-compressed request body you must do what?

Answer: Add an interceptor that sets Content-Encoding: gzip and gzips the body

Request-body compression is never automatic; you add a Content-Encoding: gzip header and wrap the RequestBody to gzip its bytes (typically with Okio's GzipSink). Transparent gzip in OkHttp applies only to responses.

Back to OkHttp & Interceptors