zoukankan      html  css  js  c++  java
  • 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     @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":"我是模拟的数据"}";//模拟的错误的返回值
    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=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":"我是模拟的数据"}
    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":"我是模拟的数据"}
    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":"我是模拟的数据"}
    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         @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 }

    复制代码

  • 相关阅读:
    bcftools 为 vcf 文件建索引及合并 vcf 文件
    Linux 替换^M字符方法
    shell 字符串分割方法简介
    shell 数组介绍及相关操作
    Annovar 信息注释
    C++ string与数值的转换
    C/C++ 删除文件 remove函数
    关于内核转储(core dump)的设置方法
    mac下nginx安装
    linux独有的sendfile系统调用--“零拷贝,高效”
  • 原文地址:https://www.cnblogs.com/exmyth/p/15124777.html
Copyright © 2011-2022 走看看