OkHttp Custom Retry Number

In this paper, OkHttp's Interceptor is used to implement a custom number of retries

Although OkHttp has its own retryOnConnectionFailure(true) method to enable retries, it does not support custom retries, so sometimes it does not meet our needs.

#1. Custom retry interceptor:

/**
 * Retry Interceptor
 */
public class RetryIntercepter implements Interceptor {

    public int maxRetry;//max retries
    private int retryNum = 0;//If set to 3 retries, the maximum possible request is 4 (default 1)+3 Second retry)

    public RetryIntercepter(int maxRetry) {
        this.maxRetry = maxRetry;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        System.out.println("retryNum=" + retryNum);
        Response response = chain.proceed(request);
        while (!response.isSuccessful() && retryNum < maxRetry) {
            retryNum++;
            System.out.println("retryNum=" + retryNum);
            response = chain.proceed(request);
        }
        return response;
    }
}

#2. Test scenario class:

 1 public class RetryTest {
 2     String mUrl = "https://www.baidu.com/";
 3     OkHttpClient mClient;
 4 
 5     @Before
 6     public void setUp() {
 7         HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
 8         logging.setLevel(HttpLoggingInterceptor.Level.BODY);
 9 
10         mClient = new OkHttpClient.Builder()
11                 .addInterceptor(new RetryIntercepter(3))//retry
12                 .addInterceptor(logging)//Network Log
13                 .addInterceptor(new TestInterceptor())//Simulate network requests
14                 .build();
15     }
16 
17     @Test
18     public void testRequest() throws IOException {
19         Request request = new Request.Builder()
20                 .url(mUrl)
21                 .build();
22         Response response = mClient.newCall(request).execute();
23         System.out.println("onResponse:" + response.body().string());
24     }
25 
26     class TestInterceptor implements Interceptor {
27 
28         @Override
29         public Response intercept(Chain chain) throws IOException {
30             Request request = chain.request();
31             String url = request.url().toString();
32             System.out.println("url=" + url);
33             Response response = null;
34             if (url.equals(mUrl)) {
35                 String responseString = "{\"message\":\"I am analogue data\"}";//Return value of simulated error
36                 response = new Response.Builder()
37                         .code(400)
38                         .request(request)
39                         .protocol(Protocol.HTTP_1_0)
40                         .body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))
41                         .addHeader("content-type", "application/json")
42                         .build();
43             } else {
44                 response = chain.proceed(request);
45             }
46             return response;
47         }
48     }
49 
50 }

#3. Output results:

 1 retryNum=0
 2 --> GET https://www.baidu.com/ HTTP/1.1
 3 --> END GET
 4 url=https://www.baidu.com/
 5 <-- 400 null https://www.baidu.com/ (13ms)
 6 content-type: application/json
 7 
 8 {"message":"I am analogue data"}
 9 <-- END HTTP (35-byte body)
10 retryNum=1
11 --> GET https://www.baidu.com/ HTTP/1.1
12 --> END GET
13 url=https://www.baidu.com/
14 <-- 400 null https://www.baidu.com/ (0ms)
15 content-type: application/json
16 
17 {"message":"I am analogue data"}
18 <-- END HTTP (35-byte body)
19 retryNum=2
20 --> GET https://www.baidu.com/ HTTP/1.1
21 --> END GET
22 url=https://www.baidu.com/
23 <-- 400 null https://www.baidu.com/ (0ms)
24 content-type: application/json
25 
26 {"message":"I am analogue data"}
27 <-- END HTTP (35-byte body)
28 retryNum=3
29 --> GET https://www.baidu.com/ HTTP/1.1
30 --> END GET
31 url=https://www.baidu.com/
32 <-- 400 null https://www.baidu.com/ (0ms)
33 content-type: application/json
34 
35 {"message":"I am analogue data"}
36 <-- END HTTP (35-byte body)
37 onResponse:{"message":"I am analogue data"}

#4. Result analysis:
>1. Here I use a TestInterceptor interceptor to intercept real network requests and customize response.code
2. In RetryIntercepter, the response code is judged by response.isSuccessful(), and chain.proceed(request) is called repeatedly to intercept retries
3. As you can see from the output, there are four requests (default 1 + retry 3).

#5. Other implementations
If you are using OkHttp+Retrofit+RxJava, you can also use the retryWhen operator: retryWhen(new RetryWithDelay()) to implement the retry mechanism

 1 public class RetryWithDelay implements Func1<Observable<? extends Throwable>, Observable<?>> {
 2 
 3         private final int maxRetries;
 4         private final int retryDelayMillis;
 5         private int retryCount;
 6 
 7         public RetryWithDelay(int maxRetries, int retryDelayMillis) {
 8             this.maxRetries = maxRetries;
 9             this.retryDelayMillis = retryDelayMillis;
10         }
11 
12         @Override
13         public Observable<?> call(Observable<? extends Throwable> attempts) {
14             return attempts
15                     .flatMap(new Func1<Throwable, Observable<?>>() {
16                         @Override
17                         public Observable<?> call(Throwable throwable) {
18                             if (++retryCount <= maxRetries) {
19                                 // When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
20                                 LogUtil.print("get error, it will try after " + retryDelayMillis + " millisecond, retry count " + retryCount);
21                                 return Observable.timer(retryDelayMillis,
22                                         TimeUnit.MILLISECONDS);
23                             }
24                             // Max retries hit. Just pass the error along.
25                             return Observable.error(throwable);
26                         }
27                     });
28         }
29 }

Tags: Android JSON OkHttp network Retrofit

Posted on Tue, 28 Apr 2020 13:05:28 -0400 by Pjack125