Retrofit 2:捕获连接超时异常

问题描述 投票:37回答:6

我具有以下设置:

final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(5, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(5, TimeUnit.SECONDS);

RestAdapter.Builder builder = new RestAdapter.Builder()
        .setEndpoint(ROOT)
        .setClient(new OkClient(okHttpClient))
        .setLogLevel(RestAdapter.LogLevel.FULL);

我正在尝试处理服务器关闭并且用户收到连接超时异常的情况,这是我的日志记录:

java.net.SocketTimeoutException: failed to connect to /192.168.0.53 (port 3000) after 5000ms

完整记录:http://pastebin.com/gscCGb7x

是否有办法将其路由到改造失败方法中,以便我可以在那里进行处理?

提前感谢!

android retrofit connection-timeout okhttp
6个回答
49
投票

用于翻新2

在您的Web服务实例中定义一个侦听器:

public interface OnConnectionTimeoutListener {
    void onConnectionTimeout();
}

将拦截器添加到您的Web服务:

public WebServiceClient() {
    OkHttpClient client = new OkHttpClient();
    client.setConnectTimeout(10, TimeUnit.SECONDS);
    client.setReadTimeout(30, TimeUnit.SECONDS);
    client.interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            return onOnIntercept(chain);
        }
    });
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();
    webService = retrofit.create(WebService.class);
}

用try-catch块围住intercep代码,并在发生异常时通知侦听器:

private Response onOnIntercept(Chain chain) throws IOException {
    try {
        Response response = chain.proceed(chain.request());
        String content = UtilityMethods.convertResponseToString(response);
        Log.d(TAG, lastCalledMethodName + " - " + content);
        return response.newBuilder().body(ResponseBody.create(response.body().contentType(), content)).build();
    }
    catch (SocketTimeoutException exception) {
        exception.printStackTrace();
        if(listener != null)
            listener.onConnectionTimeout();
    }

    return chain.proceed(chain.request());
}

37
投票
@Override
public void onFailure(Call call, Throwable t) {
    if(t instanceof SocketTimeoutException){
        message = "Socket Time out. Please try again.";
    }
}

3
投票

显然,该异常确实包含在RetrofitException中,因此您可以在故障方法中对其进行处理。


3
投票

有点复杂。使用Retrofit,您可以进行同步或异步的API调用。

如果端点返回void并有回调,则它是异步的。如果它返回某些内容并且没有回调,则它是同步的。

对于异步调用,您可以在回调的onFailure(...)方法中获得此异常。

对于同步呼叫,除非您将呼叫包装在try / catch中,否则根本无法获得。

try {
   // your synchronous call goes here  
} catch (RetrofitError error) {
   // handle errors
}

更新:上面的答案适用于翻新1.9。 Retrofit 2.0改变了很多。如果您想知道Retrofit 2.0中现在的工作方式,本文提供了一些指针http://inthecheesefactory.com/blog/retrofit-2.0/en


0
投票

如果有人带着Kotlin / Coroutines来到这里遇到同样的问题,请向您的协程范围添加一个错误处理程序:

CoroutineScope(Dispatchers.IO).launch(handler) {

而处理程序本身看起来像:

val handler = CoroutineExceptionHandler { _, exception ->
    Log.t("Network", "Caught $exception")
}

0
投票

Kotlin

如果要在Retrofit中使用Kotlin,请执行以下步骤:

定义您的改造界面:

interface GitHubApi {

    @GET("/users/{userName}/repos")
    fun repos(@Path("userName") userName: String): Call<List<Repo>>
}

实施您的服务:

class Api(...) {

    private val baseUrl = "https://api.github.com"
    private val api: GitHubApi

    private fun loggingInterceptor(...): HttpLoggingInterceptor {...}

    private fun okHttpBuilder(): OkHttpClient {...}

    init {...}

    fun repos(
        userName: String,
        onSuccess: (list: List<Repo>?) -> Unit,
        onFailure: (message: String?) -> Unit): Future<Unit> {
        return runAsync(api.repos(userName), onSuccess, onFailure)
    }

    private fun <T> runAsync(
        call: retrofit2.Call<T>,
        onSuccess: (T?) -> Unit,
        onFailure: (message: String?) -> Unit) : Future<Unit> {
        return doAsync {
            try {
                val response = call.execute()
                when {
                    response.isSuccessful -> response.body()?.let {
                        onSuccess(it)
                    }
                    else -> {
                        onFailure(response.raw().message())
                    }
                }
            } catch (e: IOException) {
                if (e is SocketTimeoutException) {
                    onFailure("Response time out!")
                } else {
                    onFailure(e.message)
                }
            }
        }
    }
}

在您需要的地方致电服务:

Api().repos("olcayertas",
    onSuccess = {
        Log.d("MainActivity", "Response:\n" + toJson(it))
    },
    onFailure = {
        Log.e("MainActivity", "Error: $it")
    })

您可以在runAsync函数中处理所需的任何异常。

您可以获得完全可用的示例here

© www.soinside.com 2019 - 2024. All rights reserved.