CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-squareup-okhttp--okhttp

An HTTP & SPDY client for Android and Java applications with efficient connection pooling, interceptors, and modern protocol support

Pending
Overview
Eval results
Files

interceptors.mddocs/

Interceptors

Request and response interception for logging, authentication, caching, and custom processing.

Capabilities

Interceptor

Observes and modifies HTTP requests/responses in processing chain.

public interface Interceptor {
    Response intercept(Chain chain) throws IOException;
    
    interface Chain {
        Request request();
        Response proceed(Request request) throws IOException;
        Connection connection();
    }
}

Chain Interface

Provides access to the request and allows proceeding with processing.

interface Chain {
    /**
     * Returns the request being processed.
     * @return the Request object
     */
    Request request();
    
    /**
     * Proceeds with the request processing, possibly after modification.
     * @param request the request to process (original or modified)
     * @return the Response from processing
     * @throws IOException if processing fails
     */
    Response proceed(Request request) throws IOException;
    
    /**
     * Returns the connection that will carry this request, or null if unknown.
     * @return the Connection or null
     */
    Connection connection();
}

Basic Usage Examples:

// Logging interceptor
class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        
        long startTime = System.nanoTime();
        System.out.println("Sending request " + request.url());
        
        Response response = chain.proceed(request);
        
        long endTime = System.nanoTime();
        System.out.println("Received response for " + response.request().url() + 
                          " in " + (endTime - startTime) / 1e6d + "ms");
        
        return response;
    }
}

// Add to client
client.interceptors().add(new LoggingInterceptor());

// Authentication interceptor
client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request.Builder requestBuilder = original.newBuilder()
            .header("Authorization", "Bearer " + getAccessToken());
        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
});

Application vs Network Interceptors

OkHttp supports two types of interceptors with different capabilities and timing.

/**
 * Application interceptors observe the full span of each call.
 * They see the original request and final response.
 */
public List<Interceptor> interceptors();

/**
 * Network interceptors observe each network request and response.
 * They see the actual network requests including redirects and retries.
 */
public List<Interceptor> networkInterceptors();

Usage Examples:

// Application interceptor - sees original request
client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        System.out.println("App interceptor: " + request.url());
        return chain.proceed(request);
    }
});

// Network interceptor - sees actual network requests
client.networkInterceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        System.out.println("Network interceptor: " + request.url());
        // This may be called multiple times for redirects
        return chain.proceed(request);
    }
});

Authentication Interceptors

Implement various authentication schemes using interceptors.

Usage Examples:

// Bearer token authentication
class BearerTokenInterceptor implements Interceptor {
    private final String token;
    
    public BearerTokenInterceptor(String token) {
        this.token = token;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request authenticated = original.newBuilder()
            .header("Authorization", "Bearer " + token)
            .build();
        return chain.proceed(authenticated);
    }
}

// API key authentication
class ApiKeyInterceptor implements Interceptor {
    private final String apiKey;
    
    public ApiKeyInterceptor(String apiKey) {
        this.apiKey = apiKey;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        HttpUrl url = original.httpUrl().newBuilder()
            .addQueryParameter("api_key", apiKey)
            .build();
        Request request = original.newBuilder()
            .url(url)
            .build();
        return chain.proceed(request);
    }
}

// Basic authentication with retry on 401
class BasicAuthInterceptor implements Interceptor {
    private final String username;
    private final String password;
    
    public BasicAuthInterceptor(String username, String password) {
        this.username = username;
        this.password = password;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        
        // Try request without auth first
        Response response = chain.proceed(original);
        
        // If 401, add auth and retry
        if (response.code() == 401) {
            response.body().close();
            String credentials = Credentials.basic(username, password);
            Request authenticated = original.newBuilder()
                .header("Authorization", credentials)
                .build();
            return chain.proceed(authenticated);
        }
        
        return response;
    }
}

Request Modification Interceptors

Modify requests before they are sent to the server.

Usage Examples:

// Add common headers
class HeaderInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request modified = original.newBuilder()
            .header("User-Agent", "MyApp/1.0")
            .header("Accept", "application/json")
            .header("X-Client-Version", "2.1.0")
            .build();
        return chain.proceed(modified);
    }
}

// URL rewriting
class UrlRewriteInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        
        // Rewrite localhost to staging server
        HttpUrl originalUrl = original.httpUrl();
        HttpUrl newUrl = originalUrl;
        
        if ("localhost".equals(originalUrl.host())) {
            newUrl = originalUrl.newBuilder()
                .host("staging.api.example.com")
                .build();
        }
        
        Request modified = original.newBuilder()
            .url(newUrl)
            .build();
        return chain.proceed(modified);
    }
}

Response Processing Interceptors

Process and modify responses before they reach the application.

Usage Examples:

// Response caching headers
class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response original = chain.proceed(chain.request());
        
        // Force cache for GET requests
        if ("GET".equals(chain.request().method())) {
            return original.newBuilder()
                .header("Cache-Control", "max-age=300")
                .build();
        }
        
        return original;
    }
}

// Error response logging
class ErrorLoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        
        if (!response.isSuccessful()) {
            System.err.printf("HTTP %d for %s: %s%n", 
                response.code(), 
                request.url(), 
                response.message());
                
            // Log response body for debugging (careful with large responses)
            if (response.body().contentLength() < 1024) {
                String bodyString = response.body().string();
                System.err.println("Error body: " + bodyString);
                
                // Create new response with same body content
                response = response.newBuilder()
                    .body(ResponseBody.create(response.body().contentType(), bodyString))
                    .build();
            }
        }
        
        return response;
    }
}

Retry and Circuit Breaker Interceptors

Implement resilience patterns using interceptors.

Usage Examples:

// Simple retry interceptor
class RetryInterceptor implements Interceptor {
    private final int maxRetries;
    
    public RetryInterceptor(int maxRetries) {
        this.maxRetries = maxRetries;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        IOException lastException = null;
        
        for (int attempt = 0; attempt <= maxRetries; attempt++) {
            try {
                if (response != null) {
                    response.body().close();
                }
                response = chain.proceed(request);
                if (response.isSuccessful() || !isRetryable(response.code())) {
                    break;
                }
            } catch (IOException e) {
                lastException = e;
                if (attempt == maxRetries) {
                    throw e;
                }
            }
            
            // Wait before retry
            try {
                Thread.sleep(1000 * (attempt + 1)); // Exponential backoff
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new IOException("Interrupted during retry", ie);
            }
        }
        
        if (response == null && lastException != null) {
            throw lastException;
        }
        
        return response;
    }
    
    private boolean isRetryable(int code) {
        return code >= 500 || code == 408 || code == 429;
    }
}

// Rate limiting interceptor
class RateLimitInterceptor implements Interceptor {
    private final long minIntervalMs;
    private volatile long lastRequestTime = 0;
    
    public RateLimitInterceptor(long minIntervalMs) {
        this.minIntervalMs = minIntervalMs;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        synchronized (this) {
            long now = System.currentTimeMillis();
            long timeSinceLastRequest = now - lastRequestTime;
            
            if (timeSinceLastRequest < minIntervalMs) {
                try {
                    Thread.sleep(minIntervalMs - timeSinceLastRequest);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new IOException("Interrupted during rate limiting", e);
                }
            }
            
            lastRequestTime = System.currentTimeMillis();
        }
        
        return chain.proceed(chain.request());
    }
}

Debugging and Monitoring Interceptors

Interceptors for debugging, monitoring, and performance analysis.

Usage Examples:

// Performance monitoring interceptor
class PerformanceInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long startTime = System.nanoTime();
        
        Response response = chain.proceed(request);
        
        long duration = System.nanoTime() - startTime;
        long durationMs = duration / 1_000_000;
        
        // Log slow requests
        if (durationMs > 1000) {
            System.out.printf("SLOW REQUEST: %s took %dms%n", request.url(), durationMs);
        }
        
        // Add timing header to response
        return response.newBuilder()
            .header("X-Response-Time", durationMs + "ms")
            .build();
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-squareup-okhttp--okhttp

docs

async-execution.md

authentication-security.md

caching.md

connection-management.md

form-data-multipart.md

http-client.md

http-utilities.md

index.md

interceptors.md

request-building.md

request-response-bodies.md

response-handling.md

tile.json