Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何使用OkHttp/Reformation重试HTTP请求?_Android_Retrofit_Okhttp - Fatal编程技术网

Android 如何使用OkHttp/Reformation重试HTTP请求?

Android 如何使用OkHttp/Reformation重试HTTP请求?,android,retrofit,okhttp,Android,Retrofit,Okhttp,我在我的Android项目中使用改型/OkHttp(1.6) 我找不到任何内置的请求重试机制。在搜索更多内容时,我看到OkHttp似乎有无声的重试。我在我的任何连接(HTTP或HTTPS)上都没有看到这种情况。如何使用okclient配置重试 目前,我正在捕获异常并尝试维护一个计数器变量。我不知道这是否是您的一个选项,但您可以与改型一起使用 改造能够在rest调用时返回可观察到的内容。在Oberservables上,您只需调用retry(count)即可在Observable发出错误时重新订阅

我在我的Android项目中使用改型/OkHttp(1.6)

我找不到任何内置的请求重试机制。在搜索更多内容时,我看到OkHttp似乎有无声的重试。我在我的任何连接(HTTP或HTTPS)上都没有看到这种情况。如何使用okclient配置重试


目前,我正在捕获异常并尝试维护一个计数器变量。

我不知道这是否是您的一个选项,但您可以与改型一起使用

改造能够在rest调用时返回可观察到的内容。在Oberservables上,您只需调用
retry(count)
即可在Observable发出错误时重新订阅

您必须在接口中定义调用,如下所示:

@GET("/data.json")
Observable<DataResponse> fetchSomeData();
restApi.fetchSomeData()
.retry(5)  // Retry the call 5 times if it errors
.subscribeOn(Schedulers.io())  // execute the call asynchronously
.observeOn(AndroidSchedulers.mainThread())  // handle the results in the ui thread
.subscribe(onComplete, onError); 
// onComplete and onError are of type Action1<DataResponse>, Action1<Throwable>
// Here you can define what to do with the results
.retryWhen(new RetryWithDelayOrInternet())
@GET(“/data.json”)
可观察的fetchSomeData();
然后你可以像这样订阅这个观测值:

@GET("/data.json")
Observable<DataResponse> fetchSomeData();
restApi.fetchSomeData()
.retry(5)  // Retry the call 5 times if it errors
.subscribeOn(Schedulers.io())  // execute the call asynchronously
.observeOn(AndroidSchedulers.mainThread())  // handle the results in the ui thread
.subscribe(onComplete, onError); 
// onComplete and onError are of type Action1<DataResponse>, Action1<Throwable>
// Here you can define what to do with the results
.retryWhen(new RetryWithDelayOrInternet())
restApi.fetchSomeData()
.retry(5)//如果呼叫出错,请重试5次
.subscribeOn(Schedulers.io())//异步执行调用
.observeOn(AndroidSchedulers.mainThread())//在ui线程中处理结果
.认购(未完成,未完成);
//onComplete和onError属于Action1类型,Action1
//在这里,您可以定义如何处理结果

我和你有同样的问题,这就是我的解决方案。RxJava是一个非常好的库,可以与改型结合使用。除了重试(例如),您甚至可以做很多很酷的事情。

API规范中的改型2.0中似乎会出现这种情况: .
目前,最好的方法似乎是捕获异常并手动重试

您可以使用方法克隆请求并执行它

用于改装1.x

你可以用。创建自定义拦截器

    OkHttpClient client = new OkHttpClient();
    client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    client.interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            // try the request
            Response response = chain.proceed(request);

            int tryCount = 0;
            while (!response.isSuccessful() && tryCount < 3) {

                Log.d("intercept", "Request is not successful - " + tryCount);

                tryCount++;

                // retry the request
                response = chain.proceed(request);
            }

            // otherwise just pass the original response on
            return response;
        }
    });
如中所述,更好的方法可能是使用烘焙式验证器,例如: 私有最终OkHttpClient客户端=新OkHttpClient()


response.issusccessful()的问题在于出现了类似SocketTimeoutException的异常

我修改了原始代码来修复它

OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        boolean responseOK = false;
        int tryCount = 0;

        while (!responseOK && tryCount < 3) {
            try {
                 response = chain.proceed(request);
                 responseOK = response.isSuccessful();                  
            }catch (Exception e){
                 Log.d("intercept", "Request is not successful - " + tryCount);                     
            }finally{
                 tryCount++;      
            }
        }

        // otherwise just pass the original response on
        return response;
    }
});
OkHttpClient=new-OkHttpClient();
setConnectTimeout(连接超时为毫秒,时间单位为毫秒);
setReadTimeout(读取超时时间为毫秒,时间单位为毫秒);
client.interceptors().add(新的Interceptor()){
@凌驾
公共响应拦截(链)引发IOException{
Request=chain.Request();
响应=空;
布尔响应k=false;
int tryCount=0;
而(!responseOK&&tryCount<3){
试一试{
响应=链。继续(请求);
responseOK=response.issusccessful();
}捕获(例外e){
Log.d(“拦截”,“请求未成功-”+tryCount);
}最后{
tryCount++;
}
}
//否则,只需将原始响应传递给
返回响应;
}
});
希望能有帮助。 尊敬。

我发现,当http连接失败时,Sinan Kozak提供的方式(OKHttpClient拦截器)不起作用,与http响应无关

因此,我使用另一种方法来钩住可观察对象,调用.retryWhen。 此外,我还增加了retryCount限制

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;
然后

例如:

return new Retrofit
        .Builder()
        .baseUrl(baseUrl)
        .client(okClient)
        .addCallAdapterFactory(newCallAdaptorFactory)
        .addConverterFactory(JacksonConverterFactory.create(objectMapper));
注意:为了简单起见,我只是将HTTP代码>404代码视为重试,请自行修改


此外,如果http响应是200,那么上面的
rx.retryWhen
将不会被调用,如果您坚持检查这样的响应,您可以添加
rx.subscribeOn(…抛出错误…
before.retryWhen.

我一直在研究这个问题,试图找到重试改装请求的最佳方法。我使用的是改装2,所以我的解决方案是改装2。对于改装1,你必须使用拦截器,就像这里接受的答案一样。@joluet的答案是正确的,但他没有提到重试m需要先调用ethod。subscribe(onComplete,onError)方法。这非常重要,否则请求不会像@joluet answer中提到的@pocmo那样再次重试。下面是我的示例:

final Observable<List<NewsDatum>> newsDetailsObservable = apiService.getCandidateNewsItem(newsId).map((newsDetailsParseObject) -> {
                    return newsDetailsParseObject;
                });

newsDetailsObservable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .retry((integer, throwable) -> {
                //MAX_NUMBER_TRY is your maximum try number
                if(integer <= MAX_NUMBER_TRY){
                    return true;//this will retry the observable (request)
                }
                return false;//this will not retry and it will go inside onError method
            })
            .subscribe(new Subscriber<List<NewsDatum>>() {
                @Override
                public void onCompleted() {
                    // do nothing
                }

                @Override
                public void onError(Throwable e) {
                   //do something with the error
                }

                @Override
                public void onNext(List<NewsDatum> apiNewsDatum) {
                    //do something with the parsed data
                }
            });
final Observable NewsDetailsBServable=apiService.getCandidateNewsItem(newsId).map((newsDetailsParseObject)->{
返回NewsDetailsSparseObject;
});
NewsDetailsBServable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.重试((整数,可丢弃)->{
//MAX\u NUMBER\u TRY是您的最大尝试次数

if(integer对于那些喜欢使用拦截器来处理重试问题的人- 基于Sinan的回答,这里是我提议的拦截器,它包括重试计数和退避延迟,并且只在网络可用且请求未取消时重试尝试。 (仅处理IOException(SocketTimeout、UnknownHost等)

builder.addInterceptor(新的拦截器(){
@凌驾
公共响应拦截(链)引发IOException{
Request=chain.Request();
//试试这个请求
响应=空;
int tryCount=1;
while(tryCount=MAX\u TRY\u COUNT){
//已达到最大重试次数,放弃
投掷e;
}
试一试{
//睡眠延迟*重试次数(例如,3000毫秒后第一次重试,6000毫秒后第二次重试等)
休眠(重试\u回退\u延迟*tryCount);
}捕捉(中断异常e1){
抛出新的运行时异常(e1);
}
tryCount++;
}
}
//否则,只需将原始响应传递给
返回响应;
}
final Observable<List<NewsDatum>> newsDetailsObservable = apiService.getCandidateNewsItem(newsId).map((newsDetailsParseObject) -> {
                    return newsDetailsParseObject;
                });

newsDetailsObservable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .retry((integer, throwable) -> {
                //MAX_NUMBER_TRY is your maximum try number
                if(integer <= MAX_NUMBER_TRY){
                    return true;//this will retry the observable (request)
                }
                return false;//this will not retry and it will go inside onError method
            })
            .subscribe(new Subscriber<List<NewsDatum>>() {
                @Override
                public void onCompleted() {
                    // do nothing
                }

                @Override
                public void onError(Throwable e) {
                   //do something with the error
                }

                @Override
                public void onNext(List<NewsDatum> apiNewsDatum) {
                    //do something with the parsed data
                }
            });
    builder.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            // try the request
            Response response = null;
            int tryCount = 1;
            while (tryCount <= MAX_TRY_COUNT) {
                try {
                    response = chain.proceed(request);
                    break;
                } catch (Exception e) {
                    if (!NetworkUtils.isNetworkAvailable()) {
                        // if no internet, dont bother retrying request
                        throw e;
                    }
                    if ("Canceled".equalsIgnoreCase(e.getMessage())) {
                        // Request canceled, do not retry
                        throw e;
                    }
                    if (tryCount >= MAX_TRY_COUNT) {
                        // max retry count reached, giving up
                        throw e;
                    }

                    try {
                        // sleep delay * try count (e.g. 1st retry after 3000ms, 2nd after 6000ms, etc.)
                        Thread.sleep(RETRY_BACKOFF_DELAY * tryCount);
                    } catch (InterruptedException e1) {
                        throw new RuntimeException(e1);
                    }
                    tryCount++;
                }
            }

            // otherwise just pass the original response on
            return response;
        }
    });
public class ErrorInterceptor implements Interceptor {
ICacheManager cacheManager;
Response response = null;
int tryCount = 0;
int maxLimit = 3;
int waitThreshold = 5000;
@Inject
public ErrorInterceptor() {

}

@Override
public Response intercept(Chain chain){

   // String language =  cacheManager.readPreference(PreferenceKeys.LANGUAGE_CODE);
  Request request = chain.request();
  response =  sendReqeust(chain,request);
    while (response ==null && tryCount < maxLimit) {
        Log.d("intercept", "Request failed - " + tryCount);
        tryCount++;
        try {
            Thread.sleep(waitThreshold); // force wait the network thread for 5 seconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       response = sendReqeust(chain,request);
    }
    return response;
}

private Response sendReqeust(Chain chain, Request request){
    try {
        response = chain.proceed(request);
        if(!response.isSuccessful())
            return null;
        else
        return response;
    } catch (IOException e) {
      return null;
    }
}
public class RetryWithDelayOrInternet implements Function<Flowable<? extends Throwable>, Flowable<?>> {
public static boolean isInternetUp;
private int retryCount;

@Override
public Flowable<?> apply(final Flowable<? extends Throwable> attempts) {
    return Flowable.fromPublisher(s -> {
        while (true) {
            retryCount++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                attempts.subscribe(s);
                break;
            }
            if (isInternetUp || retryCount == 15) {
                retryCount = 0;
                s.onNext(new Object());
            }
        }
    })
            .subscribeOn(Schedulers.single());
}}
.retryWhen(new RetryWithDelayOrInternet())
public class InternetConnectionReceiver extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {
    boolean networkAvailable = isNetworkAvailable(context);
    RetryWithDelayOrInternet.isInternetUp = networkAvailable;
}
public static boolean isNetworkAvailable(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}}
AuthenticationResponse authResp = Failsafe.with(
new RetryPolicy().retryOn(Arrays.asList(IOException.class, AssertionError.class))
        .withBackoff(30, 500, TimeUnit.MILLISECONDS)
        .withMaxRetries(3))
.onRetry((error) -> logger.warn("Retrying after error: " + error.getMessage()))
.get(() -> {
    AuthenticationResponse r = mySimpleAPIService.authenticate(
            new AuthenticationRequest(username,password))
            .execute()
            .body();

    assert r != null;

    return r;
});
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
    Request  request      = chain.request();
    int      retriesCount = 0;
    Response response     = null;

    do {
        try {
            response = chain.proceed(request);

        // Retry if no internet connection.
        } catch (ConnectException e) {
            Log.e(TAG, "intercept: ", e);
            retriesCount++;

            try {
                Thread.sleep(RETRY_TIME);

            } catch (InterruptedException e1) {
                Log.e(TAG, "intercept: ", e1);
            }
        }

    } while (response == null && retriesCount < MAX_RETRIES);

    // If there was no internet connection, then response will be null.
    // Need to initialize response anyway to avoid NullPointerException.
    if (response == null) {
        response = chain.proceed(newRequest);
    }

    return response;
}
public int callAPI() {
    return 1; //some method to be retried
}

public int retrylogic()  throws InterruptedException, IOException{
    int retry = 0;
    int status = -1;
    boolean delay = false;
    do {
        if (delay) {
            Thread.sleep(2000);
        }

        try {
            status = callAPI();
        }
        catch (Exception e) {
            System.out.println("Error occured");
            status = -1;
        }
        finally {
            switch (status) {
            case 200:
                System.out.println(" **OK**");
                return status; 
            default:
                System.out.println(" **unknown response code**.");
                break;
            }
            retry++;
            System.out.println("Failed retry " + retry + "/" + 3);
            delay = true;

        } 
    }while (retry < 3);

    System.out.println("Aborting download of dataset.");
    return status;
}