87

Android プロジェクトで Retrofit/OkHttp (1.6) を使用しています。

どちらにも組み込まれているリクエスト再試行メカニズムは見つかりません。さらに検索すると、OkHttpにはサイレントリトライがあるようです。私の接続(HTTPまたはHTTPS)でそれが起こっていることはわかりません。okclient で再試行を構成する方法は?

今のところ、例外をキャッチして、カウンター変数の維持を再試行しています。

4

15 に答える 15

95

レトロフィット 2.x の場合。

Call.clone()メソッドを使用して、リクエストを複製して実行できます。

レトロフィット 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;
        }
    });

RestAdapter の作成中に使用します。

new RestAdapter.Builder()
        .setEndpoint(API_URL)
        .setRequestInterceptor(requestInterceptor)
        .setClient(new OkClient(client))
        .build()
        .create(Adapter.class);
于 2015-07-30T20:41:35.897 に答える
13

response.isSuccessful() の問題は、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;
    }
});

それが役に立てば幸い。よろしく。

于 2015-12-21T20:51:30.483 に答える
2

再試行の問題に対処するためにインターセプターを好む人のために-シナンの答えに基づいて、ここに私の提案したインターセプターがあります。キャンセル。(IOExceptions (SocketTimeout、UnknownHost など) のみを処理します)

    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;
        }
    });
于 2016-08-06T12:29:42.350 に答える
1

私のバージョンを共有したいだけです。rxJava の retryWhen メソッドを使用します。私のバージョンは N=15 秒ごとに接続を再試行し、インターネット接続が回復するとすぐに再試行します。

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());
}}

そして、次のように .subscribe の前に使用する必要があります。

.retryWhen(new RetryWithDelayOrInternet())

isInternetUp フィールドを手動で変更する必要があります

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();
}}
于 2018-02-14T13:59:58.627 に答える
0

docsに記載されているように、焼き付けられたオーセンティケーターを使用することをお勧めします。

  public void run() throws Exception {
    client.setAuthenticator(new Authenticator() {
      @Override public Request authenticate(Proxy proxy, Response response) {
        System.out.println("Authenticating for response: " + response);
        System.out.println("Challenges: " + response.challenges());
        String credential = Credentials.basic("jesse", "password1");
        return response.request().newBuilder()
            .header("Authorization", credential)
            .build();
      }

      @Override public Request authenticateProxy(Proxy proxy, Response response) {
        return null; // Null indicates no attempt to authenticate.
      }
    });

    Request request = new Request.Builder()
        .url("http://publicobject.com/secrets/hellosecret.txt")
        .build();

    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

    System.out.println(response.body().string());
  }
于 2015-12-11T00:38:35.390 に答える
0

API Spec: https://github.com/square/retrofit/issues/297からレトロフィット 2.0 に存在するよう です。現在、最善の方法は、例外をキャッチして手動で再試行することです。

于 2014-10-22T21:04:01.653 に答える