or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-execution.mdauthentication-security.mdcaching.mdconnection-management.mdform-data-multipart.mdhttp-client.mdhttp-utilities.mdindex.mdinterceptors.mdrequest-building.mdrequest-response-bodies.mdresponse-handling.md

interceptors.mddocs/

0

# Interceptors

1

2

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

3

4

## Capabilities

5

6

### Interceptor

7

8

Observes and modifies HTTP requests/responses in processing chain.

9

10

```java { .api }

11

public interface Interceptor {

12

Response intercept(Chain chain) throws IOException;

13

14

interface Chain {

15

Request request();

16

Response proceed(Request request) throws IOException;

17

Connection connection();

18

}

19

}

20

```

21

22

### Chain Interface

23

24

Provides access to the request and allows proceeding with processing.

25

26

```java { .api }

27

interface Chain {

28

/**

29

* Returns the request being processed.

30

* @return the Request object

31

*/

32

Request request();

33

34

/**

35

* Proceeds with the request processing, possibly after modification.

36

* @param request the request to process (original or modified)

37

* @return the Response from processing

38

* @throws IOException if processing fails

39

*/

40

Response proceed(Request request) throws IOException;

41

42

/**

43

* Returns the connection that will carry this request, or null if unknown.

44

* @return the Connection or null

45

*/

46

Connection connection();

47

}

48

```

49

50

**Basic Usage Examples:**

51

52

```java

53

// Logging interceptor

54

class LoggingInterceptor implements Interceptor {

55

@Override

56

public Response intercept(Chain chain) throws IOException {

57

Request request = chain.request();

58

59

long startTime = System.nanoTime();

60

System.out.println("Sending request " + request.url());

61

62

Response response = chain.proceed(request);

63

64

long endTime = System.nanoTime();

65

System.out.println("Received response for " + response.request().url() +

66

" in " + (endTime - startTime) / 1e6d + "ms");

67

68

return response;

69

}

70

}

71

72

// Add to client

73

client.interceptors().add(new LoggingInterceptor());

74

75

// Authentication interceptor

76

client.interceptors().add(new Interceptor() {

77

@Override

78

public Response intercept(Chain chain) throws IOException {

79

Request original = chain.request();

80

Request.Builder requestBuilder = original.newBuilder()

81

.header("Authorization", "Bearer " + getAccessToken());

82

Request request = requestBuilder.build();

83

return chain.proceed(request);

84

}

85

});

86

```

87

88

### Application vs Network Interceptors

89

90

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

91

92

```java { .api }

93

/**

94

* Application interceptors observe the full span of each call.

95

* They see the original request and final response.

96

*/

97

public List<Interceptor> interceptors();

98

99

/**

100

* Network interceptors observe each network request and response.

101

* They see the actual network requests including redirects and retries.

102

*/

103

public List<Interceptor> networkInterceptors();

104

```

105

106

**Usage Examples:**

107

108

```java

109

// Application interceptor - sees original request

110

client.interceptors().add(new Interceptor() {

111

@Override

112

public Response intercept(Chain chain) throws IOException {

113

Request request = chain.request();

114

System.out.println("App interceptor: " + request.url());

115

return chain.proceed(request);

116

}

117

});

118

119

// Network interceptor - sees actual network requests

120

client.networkInterceptors().add(new Interceptor() {

121

@Override

122

public Response intercept(Chain chain) throws IOException {

123

Request request = chain.request();

124

System.out.println("Network interceptor: " + request.url());

125

// This may be called multiple times for redirects

126

return chain.proceed(request);

127

}

128

});

129

```

130

131

### Authentication Interceptors

132

133

Implement various authentication schemes using interceptors.

134

135

**Usage Examples:**

136

137

```java

138

// Bearer token authentication

139

class BearerTokenInterceptor implements Interceptor {

140

private final String token;

141

142

public BearerTokenInterceptor(String token) {

143

this.token = token;

144

}

145

146

@Override

147

public Response intercept(Chain chain) throws IOException {

148

Request original = chain.request();

149

Request authenticated = original.newBuilder()

150

.header("Authorization", "Bearer " + token)

151

.build();

152

return chain.proceed(authenticated);

153

}

154

}

155

156

// API key authentication

157

class ApiKeyInterceptor implements Interceptor {

158

private final String apiKey;

159

160

public ApiKeyInterceptor(String apiKey) {

161

this.apiKey = apiKey;

162

}

163

164

@Override

165

public Response intercept(Chain chain) throws IOException {

166

Request original = chain.request();

167

HttpUrl url = original.httpUrl().newBuilder()

168

.addQueryParameter("api_key", apiKey)

169

.build();

170

Request request = original.newBuilder()

171

.url(url)

172

.build();

173

return chain.proceed(request);

174

}

175

}

176

177

// Basic authentication with retry on 401

178

class BasicAuthInterceptor implements Interceptor {

179

private final String username;

180

private final String password;

181

182

public BasicAuthInterceptor(String username, String password) {

183

this.username = username;

184

this.password = password;

185

}

186

187

@Override

188

public Response intercept(Chain chain) throws IOException {

189

Request original = chain.request();

190

191

// Try request without auth first

192

Response response = chain.proceed(original);

193

194

// If 401, add auth and retry

195

if (response.code() == 401) {

196

response.body().close();

197

String credentials = Credentials.basic(username, password);

198

Request authenticated = original.newBuilder()

199

.header("Authorization", credentials)

200

.build();

201

return chain.proceed(authenticated);

202

}

203

204

return response;

205

}

206

}

207

```

208

209

### Request Modification Interceptors

210

211

Modify requests before they are sent to the server.

212

213

**Usage Examples:**

214

215

```java

216

// Add common headers

217

class HeaderInterceptor implements Interceptor {

218

@Override

219

public Response intercept(Chain chain) throws IOException {

220

Request original = chain.request();

221

Request modified = original.newBuilder()

222

.header("User-Agent", "MyApp/1.0")

223

.header("Accept", "application/json")

224

.header("X-Client-Version", "2.1.0")

225

.build();

226

return chain.proceed(modified);

227

}

228

}

229

230

// URL rewriting

231

class UrlRewriteInterceptor implements Interceptor {

232

@Override

233

public Response intercept(Chain chain) throws IOException {

234

Request original = chain.request();

235

236

// Rewrite localhost to staging server

237

HttpUrl originalUrl = original.httpUrl();

238

HttpUrl newUrl = originalUrl;

239

240

if ("localhost".equals(originalUrl.host())) {

241

newUrl = originalUrl.newBuilder()

242

.host("staging.api.example.com")

243

.build();

244

}

245

246

Request modified = original.newBuilder()

247

.url(newUrl)

248

.build();

249

return chain.proceed(modified);

250

}

251

}

252

```

253

254

### Response Processing Interceptors

255

256

Process and modify responses before they reach the application.

257

258

**Usage Examples:**

259

260

```java

261

// Response caching headers

262

class CacheInterceptor implements Interceptor {

263

@Override

264

public Response intercept(Chain chain) throws IOException {

265

Response original = chain.proceed(chain.request());

266

267

// Force cache for GET requests

268

if ("GET".equals(chain.request().method())) {

269

return original.newBuilder()

270

.header("Cache-Control", "max-age=300")

271

.build();

272

}

273

274

return original;

275

}

276

}

277

278

// Error response logging

279

class ErrorLoggingInterceptor implements Interceptor {

280

@Override

281

public Response intercept(Chain chain) throws IOException {

282

Request request = chain.request();

283

Response response = chain.proceed(request);

284

285

if (!response.isSuccessful()) {

286

System.err.printf("HTTP %d for %s: %s%n",

287

response.code(),

288

request.url(),

289

response.message());

290

291

// Log response body for debugging (careful with large responses)

292

if (response.body().contentLength() < 1024) {

293

String bodyString = response.body().string();

294

System.err.println("Error body: " + bodyString);

295

296

// Create new response with same body content

297

response = response.newBuilder()

298

.body(ResponseBody.create(response.body().contentType(), bodyString))

299

.build();

300

}

301

}

302

303

return response;

304

}

305

}

306

```

307

308

### Retry and Circuit Breaker Interceptors

309

310

Implement resilience patterns using interceptors.

311

312

**Usage Examples:**

313

314

```java

315

// Simple retry interceptor

316

class RetryInterceptor implements Interceptor {

317

private final int maxRetries;

318

319

public RetryInterceptor(int maxRetries) {

320

this.maxRetries = maxRetries;

321

}

322

323

@Override

324

public Response intercept(Chain chain) throws IOException {

325

Request request = chain.request();

326

Response response = null;

327

IOException lastException = null;

328

329

for (int attempt = 0; attempt <= maxRetries; attempt++) {

330

try {

331

if (response != null) {

332

response.body().close();

333

}

334

response = chain.proceed(request);

335

if (response.isSuccessful() || !isRetryable(response.code())) {

336

break;

337

}

338

} catch (IOException e) {

339

lastException = e;

340

if (attempt == maxRetries) {

341

throw e;

342

}

343

}

344

345

// Wait before retry

346

try {

347

Thread.sleep(1000 * (attempt + 1)); // Exponential backoff

348

} catch (InterruptedException ie) {

349

Thread.currentThread().interrupt();

350

throw new IOException("Interrupted during retry", ie);

351

}

352

}

353

354

if (response == null && lastException != null) {

355

throw lastException;

356

}

357

358

return response;

359

}

360

361

private boolean isRetryable(int code) {

362

return code >= 500 || code == 408 || code == 429;

363

}

364

}

365

366

// Rate limiting interceptor

367

class RateLimitInterceptor implements Interceptor {

368

private final long minIntervalMs;

369

private volatile long lastRequestTime = 0;

370

371

public RateLimitInterceptor(long minIntervalMs) {

372

this.minIntervalMs = minIntervalMs;

373

}

374

375

@Override

376

public Response intercept(Chain chain) throws IOException {

377

synchronized (this) {

378

long now = System.currentTimeMillis();

379

long timeSinceLastRequest = now - lastRequestTime;

380

381

if (timeSinceLastRequest < minIntervalMs) {

382

try {

383

Thread.sleep(minIntervalMs - timeSinceLastRequest);

384

} catch (InterruptedException e) {

385

Thread.currentThread().interrupt();

386

throw new IOException("Interrupted during rate limiting", e);

387

}

388

}

389

390

lastRequestTime = System.currentTimeMillis();

391

}

392

393

return chain.proceed(chain.request());

394

}

395

}

396

```

397

398

### Debugging and Monitoring Interceptors

399

400

Interceptors for debugging, monitoring, and performance analysis.

401

402

**Usage Examples:**

403

404

```java

405

// Performance monitoring interceptor

406

class PerformanceInterceptor implements Interceptor {

407

@Override

408

public Response intercept(Chain chain) throws IOException {

409

Request request = chain.request();

410

long startTime = System.nanoTime();

411

412

Response response = chain.proceed(request);

413

414

long duration = System.nanoTime() - startTime;

415

long durationMs = duration / 1_000_000;

416

417

// Log slow requests

418

if (durationMs > 1000) {

419

System.out.printf("SLOW REQUEST: %s took %dms%n", request.url(), durationMs);

420

}

421

422

// Add timing header to response

423

return response.newBuilder()

424

.header("X-Response-Time", durationMs + "ms")

425

.build();

426

}

427

}

428

```