OkHttpConfig.java 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package com.zsElectric.boot.config;
  2. import lombok.extern.slf4j.Slf4j;
  3. import okhttp3.ConnectionPool;
  4. import okhttp3.Interceptor;
  5. import okhttp3.OkHttpClient;
  6. import okhttp3.Request;
  7. import okhttp3.Response;
  8. import org.springframework.beans.factory.annotation.Value;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import java.io.IOException;
  12. import java.net.SocketTimeoutException;
  13. import java.time.Duration;
  14. import java.util.concurrent.TimeUnit;
  15. @Slf4j
  16. @Configuration
  17. public class OkHttpConfig {
  18. @Value("${okhttp.connect-timeout:30}")
  19. private Duration connectTimeout;
  20. @Value("${okhttp.read-timeout:120}")
  21. private Duration readTimeout;
  22. @Value("${okhttp.write-timeout:60}")
  23. private Duration writeTimeout;
  24. @Value("${okhttp.retry-on-connection-failure:true}")
  25. private boolean retryOnConnectionFailure;
  26. @Value("${okhttp.connection-pool.max-idle-connections:200}")
  27. private int maxIdleConnections;
  28. @Value("${okhttp.connection-pool.keep-alive-duration:300}")
  29. private Duration keepAliveDuration;
  30. @Value("${okhttp.max-retry-count:2}")
  31. private int maxRetryCount;
  32. @Bean
  33. public ConnectionPool connectionPool() {
  34. return new ConnectionPool(maxIdleConnections, keepAliveDuration.toMillis(), TimeUnit.MILLISECONDS);
  35. }
  36. @Bean
  37. public OkHttpClient okHttpClient(ConnectionPool connectionPool) {
  38. return new OkHttpClient.Builder()
  39. .connectTimeout(connectTimeout)
  40. .readTimeout(readTimeout)
  41. .writeTimeout(writeTimeout)
  42. .retryOnConnectionFailure(retryOnConnectionFailure)
  43. .connectionPool(connectionPool)
  44. .addInterceptor(retryInterceptor())
  45. .build();
  46. }
  47. /**
  48. * 重试拦截器
  49. */
  50. private Interceptor retryInterceptor() {
  51. return chain -> {
  52. Request request = chain.request();
  53. Response response = null;
  54. IOException lastException = null;
  55. for (int i = 0; i <= maxRetryCount; i++) {
  56. try {
  57. if (i > 0) {
  58. log.warn("第 {} 次重试请求: {}", i, request.url());
  59. // 重试前等待一段时间,使用指数退避策略
  60. // 第1次重试等待2秒,第2次等待4秒
  61. long waitTime = (long) Math.pow(2, i) * 1000;
  62. log.info("重试前等待 {} 毫秒", waitTime);
  63. Thread.sleep(waitTime);
  64. }
  65. response = chain.proceed(request);
  66. // 如果响应成功,直接返回
  67. if (response.isSuccessful()) {
  68. if (i > 0) {
  69. log.info("第 {} 次重试成功: {}", i, request.url());
  70. }
  71. return response;
  72. }
  73. // 如果是客户端错误(4xx),不重试
  74. if (response.code() >= 400 && response.code() < 500) {
  75. log.warn("客户端错误,不重试: {}, 状态码: {}", request.url(), response.code());
  76. return response;
  77. }
  78. } catch (SocketTimeoutException e) {
  79. lastException = e;
  80. log.error("请求超时: {}, 第 {} 次尝试", request.url(), i + 1, e);
  81. if (response != null) {
  82. response.close();
  83. }
  84. } catch (IOException e) {
  85. lastException = e;
  86. log.error("请求失败: {}, 第 {} 次尝试", request.url(), i + 1, e);
  87. if (response != null) {
  88. response.close();
  89. }
  90. } catch (InterruptedException e) {
  91. Thread.currentThread().interrupt();
  92. throw new IOException("重试被中断", e);
  93. }
  94. }
  95. // 所有重试都失败了
  96. if (lastException != null) {
  97. log.error("所有重试都失败了: {}, 总共尝试 {} 次", request.url(), maxRetryCount + 1);
  98. throw lastException;
  99. }
  100. return response;
  101. };
  102. }
  103. }