OkHttp自訂重試次數,okhttp自訂重試
本文主要應用了OkHttp的Interceptor來實現自訂重試次數
雖然OkHttp內建retryOnConnectionFailure(true)方法可以實現重試,但是不支援自訂重試次數,所以有時並不能滿足我們的需求。
#1.自訂重試攔截器:
/** * 重試攔截器 */public class RetryIntercepter implements Interceptor { public int maxRetry;//最大重試次數 private int retryNum = 0;//假如設定為3次重試的話,則最大可能請求4次(預設1次+3次重試) 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.測試情境類:
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))//重試12 .addInterceptor(logging)//部落格13 .addInterceptor(new TestInterceptor())//類比網路請求14 .build();15 }16 17 @Test18 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 @Override29 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\":\"我是類比的資料\"}";//類比的錯誤的傳回值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.輸出結果:
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":"我是類比的資料"} 9 <-- END HTTP (35-byte body)10 retryNum=111 --> GET https://www.baidu.com/ HTTP/1.112 --> END GET13 url=https://www.baidu.com/14 <-- 400 null https://www.baidu.com/ (0ms)15 content-type: application/json16 17 {"message":"我是類比的資料"}18 <-- END HTTP (35-byte body)19 retryNum=220 --> GET https://www.baidu.com/ HTTP/1.121 --> END GET22 url=https://www.baidu.com/23 <-- 400 null https://www.baidu.com/ (0ms)24 content-type: application/json25 26 {"message":"我是類比的資料"}27 <-- END HTTP (35-byte body)28 retryNum=329 --> GET https://www.baidu.com/ HTTP/1.130 --> END GET31 url=https://www.baidu.com/32 <-- 400 null https://www.baidu.com/ (0ms)33 content-type: application/json34 35 {"message":"我是類比的資料"}36 <-- END HTTP (35-byte body)37 onResponse:{"message":"我是類比的資料"}
#4.結果分析:
>1. 這裡我用一個TestInterceptor攔截器攔截掉真實的網路請求,實現response.code的自訂
2. 在RetryIntercepter中,通過response.isSuccessful()來對響應碼進行判斷,迴圈調用了多次chain.proceed(request)來實現重試攔截
3. 從輸出中可以看到,一共請求了4次(預設1次+重試3次)。
#5.其它實現方式
如果你是使用OkHttp+Retrofit+RxJava,你也可以使用retryWhen操作符:retryWhen(new RetryWithDelay())來實現重試機制
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 @Override13 public Observable<?> call(Observable<? extends Throwable> attempts) {14 return attempts15 .flatMap(new Func1<Throwable, Observable<?>>() {16 @Override17 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 }