Android プロジェクトで Retrofit/OkHttp (1.6) を使用しています。
どちらにも組み込まれているリクエスト再試行メカニズムは見つかりません。さらに検索すると、OkHttpにはサイレントリトライがあるようです。私の接続(HTTPまたはHTTPS)でそれが起こっていることはわかりません。okclient で再試行を構成する方法は?
今のところ、例外をキャッチして、カウンター変数の維持を再試行しています。
レトロフィット 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);
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;
}
});
それが役に立てば幸い。よろしく。
再試行の問題に対処するためにインターセプターを好む人のために-シナンの答えに基づいて、ここに私の提案したインターセプターがあります。キャンセル。(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;
}
});
私のバージョンを共有したいだけです。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();
}}
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());
}
API Spec: https://github.com/square/retrofit/issues/297からレトロフィット 2.0 に存在するよう です。現在、最善の方法は、例外をキャッチして手動で再試行することです。