How to retry HTTP requests with OkHttp/Retrofit?

后端 未结 13 721
一向
一向 2020-12-07 09:04

I am using Retrofit/OkHttp (1.6) in my Android project.

I don\'t find any request retry mechanism built-in to either of them. On searching more, I read OkHttp seems

相关标签:
13条回答
  • 2020-12-07 10:06

    I found the way(OKHttpClient intercepter) provided by Sinan Kozak does not work when http connection failed, there is nothing yet concerned with HTTP response.

    So i use another way to hook the Observable object, call .retryWhen on it. Also, i have added retryCount limit.

    import retrofit2.Call;
    import retrofit2.CallAdapter;
    import retrofit2.Retrofit;
    import retrofit2.adapter.rxjava.HttpException;
    import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
    import retrofit2.converter.jackson.JacksonConverterFactory;
    import rx.Observable;
    import java.io.IOException;
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Type;
    

    Then

        RxJavaCallAdapterFactory originCallAdaptorFactory = RxJavaCallAdapterFactory.create();
    
        CallAdapter.Factory newCallAdaptorFactory = new CallAdapter.Factory() {
            @Override
            public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    
                CallAdapter<?> ca = originCallAdaptorFactory.get(returnType, annotations, retrofit);
    
                return new CallAdapter<Observable<?>>() {
    
                    @Override
                    public Type responseType() {
                        return ca.responseType();
                    }
    
                    int restRetryCount = 3;
    
                    @Override
                    public <R> Observable<?> adapt(Call<R> call) {
                        Observable<?> rx = (Observable<?>) ca.adapt(call);
    
                        return rx.retryWhen(errors -> errors.flatMap(error -> {
                            boolean needRetry = false;
                            if (restRetryCount >= 1) {
                                if (error instanceof IOException) {
                                    needRetry = true;
                                } else if (error instanceof HttpException) {
                                    if (((HttpException) error).code() != 200) {
                                        needRetry = true;
                                    }
                                }
                            }
    
                            if (needRetry) {
                                restRetryCount--;
                                return Observable.just(null);
                            } else {
                                return Observable.error(error);
                            }
                        }));
                    }
                };
            }
        };                
    

    Then add or replace

    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    

    with

    .addCallAdapterFactory(newCallAdaptorFactory)
    

    For example:

    return new Retrofit
            .Builder()
            .baseUrl(baseUrl)
            .client(okClient)
            .addCallAdapterFactory(newCallAdaptorFactory)
            .addConverterFactory(JacksonConverterFactory.create(objectMapper));
    

    Note: For simplicity, i just treat HTTP code > 404 code as retry, please modify it for yourself.

    Besides, if http response is 200, then above rx.retryWhen will not get called, if you insist check such a response, you can add rx.subscribeOn(...throw error... before .retryWhen.

    0 讨论(0)
提交回复
热议问题