package com.zsElectric.boot.config; import lombok.extern.slf4j.Slf4j; import okhttp3.ConnectionPool; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; import java.net.SocketTimeoutException; import java.time.Duration; import java.util.concurrent.TimeUnit; @Slf4j @Configuration public class OkHttpConfig { @Value("${okhttp.connect-timeout:30}") private Duration connectTimeout; @Value("${okhttp.read-timeout:120}") private Duration readTimeout; @Value("${okhttp.write-timeout:60}") private Duration writeTimeout; @Value("${okhttp.retry-on-connection-failure:true}") private boolean retryOnConnectionFailure; @Value("${okhttp.connection-pool.max-idle-connections:200}") private int maxIdleConnections; @Value("${okhttp.connection-pool.keep-alive-duration:300}") private Duration keepAliveDuration; @Value("${okhttp.max-retry-count:2}") private int maxRetryCount; @Bean public ConnectionPool connectionPool() { return new ConnectionPool(maxIdleConnections, keepAliveDuration.toMillis(), TimeUnit.MILLISECONDS); } @Bean public OkHttpClient okHttpClient(ConnectionPool connectionPool) { return new OkHttpClient.Builder() .connectTimeout(connectTimeout) .readTimeout(readTimeout) .writeTimeout(writeTimeout) .retryOnConnectionFailure(retryOnConnectionFailure) .connectionPool(connectionPool) .addInterceptor(retryInterceptor()) .build(); } /** * 重试拦截器 */ private Interceptor retryInterceptor() { return chain -> { Request request = chain.request(); Response response = null; IOException lastException = null; for (int i = 0; i <= maxRetryCount; i++) { try { if (i > 0) { log.warn("第 {} 次重试请求: {}", i, request.url()); // 重试前等待一段时间,使用指数退避策略 // 第1次重试等待2秒,第2次等待4秒 long waitTime = (long) Math.pow(2, i) * 1000; log.info("重试前等待 {} 毫秒", waitTime); Thread.sleep(waitTime); } response = chain.proceed(request); // 如果响应成功,直接返回 if (response.isSuccessful()) { if (i > 0) { log.info("第 {} 次重试成功: {}", i, request.url()); } return response; } // 如果是客户端错误(4xx),不重试 if (response.code() >= 400 && response.code() < 500) { log.warn("客户端错误,不重试: {}, 状态码: {}", request.url(), response.code()); return response; } } catch (SocketTimeoutException e) { lastException = e; log.error("请求超时: {}, 第 {} 次尝试", request.url(), i + 1, e); if (response != null) { response.close(); } } catch (IOException e) { lastException = e; log.error("请求失败: {}, 第 {} 次尝试", request.url(), i + 1, e); if (response != null) { response.close(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException("重试被中断", e); } } // 所有重试都失败了 if (lastException != null) { log.error("所有重试都失败了: {}, 总共尝试 {} 次", request.url(), maxRetryCount + 1); throw lastException; } return response; }; } }