Retrofit和OkHttpClient,在失败方法中捕获连接超时

Jdr*_*uwe 37 android connection-timeout retrofit okhttp

我有以下设置:

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);
Run Code Online (Sandbox Code Playgroud)

我试图处理我的服务器关闭和用户获得连接超时异常的情况,这是我的日志记录:

java.net.SocketTimeoutException: failed to connect to /192.168.0.53 (port 3000) after 5000ms
Run Code Online (Sandbox Code Playgroud)

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

有没有办法将其转换为改装故障方法,以便我可以在那里处理它?

提前致谢!

Olc*_*taş 49

对于改造2

在Web服务实例中定义侦听器:

public interface OnConnectionTimeoutListener {
    void onConnectionTimeout();
}
Run Code Online (Sandbox Code Playgroud)

向您的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);
}
Run Code Online (Sandbox Code Playgroud)

使用try-catch块封闭您的拦截代码,并在发生异常时通知侦听器:

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());
}
Run Code Online (Sandbox Code Playgroud)

  • `UtilityMethods.convertResponseToString(response);`来自哪里? (4认同)
  • 这个拦截器很棒,但是当我的订阅者的 onError(Throwable t) 中发生 TimeoutException 时,我得到以下信息: t.getMessage() = "网络拦截器 com.test.presentation.application.di.AppRestModule$2@2320fd48 必须准确调用proceed()一次”。这可以吗?或者也许我们不应该第二次调用继续? (2认同)
  • UtilityMethods.convertResponseToString(响应) - 这究竟是做什么的? (2认同)

小智 37

@Override
public void onFailure(Call call, Throwable t) {
    if(t instanceof SocketTimeoutException){
        message = "Socket Time out. Please try again.";
    }
}
Run Code Online (Sandbox Code Playgroud)


car*_*l7j 9

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

CoroutineScope(Dispatchers.IO).launch(handler) {
Run Code Online (Sandbox Code Playgroud)

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

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


SVP*_*SVP 6

这些答案都不适合我,但它们引导我走向正确的方向。请参阅下面我如何在 Kotlin 中做到这一点。

ErrorInterceptor您可以在 api 调用函数中抛出异常并捕获它们:

class ErrorInterceptor : Interceptor {

    override fun intercept(chain: Chain): Response {

        val request = chain.request()

        try {
            val response = chain.proceed(request)
            val bodyString = response.body!!.string()

            return response.newBuilder()
                .body(bodyString.toResponseBody(response.body?.contentType()))
                .build()
        } catch (e: Exception) {
            when (e) {
                is SocketTimeoutException -> {
                    throw SocketTimeoutException()
                }

               // Add additional errors... //

            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

或者将异常与响应对象捆绑在一起;像这样的东西:

class ErrorInterceptor : Interceptor {

    override fun intercept(chain: Chain): Response {

        val request = chain.request()

        try {
            val response = chain.proceed(request)
            val bodyString = response.body!!.string()

            return response.newBuilder()
                .body(bodyString.toResponseBody(response.body?.contentType()))
                .build()
        } catch (e: Exception) {
            var msg = ""
            val interceptorCode: Int

            when (e) {
                is SocketTimeoutException -> {

                    msg = "Socket timeout error"
                    interceptorCode = 408

                }

               // Add additional errors... //

            }

             return Response.Builder()
                .request(request)
                .protocol(Protocol.HTTP_1_1)
                .code(interceptorCode)
                .message(msg)
                .body("{${e}}".toResponseBody(null)).build()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

添加ErrorInterceptor到您的okHttpClient

okHttpClient.newBuilder()
                .addInterceptor(ErrorInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                 // ... //
                .build()
Run Code Online (Sandbox Code Playgroud)

然后在您的存储库层中执行类似的操作:

suspend fun makeAPIRequest(): Resource<ApiResponse> {

        return withContext(ioDispatcher) {

            var response: Response<ApiResponse>? = null

            try {
                response = getResponse()

                // Do additional ops on response here //

            } catch (e: Exception) {

                // Exceptions thrown in ErrorInterceptor will propagate here

            }
        }
    }
Run Code Online (Sandbox Code Playgroud)