【问题标题】:Retrofit & okhttp won't work after I turn on internet on phone我在手机上打开互联网后,改造和 okhttp 将不起作用
【发布时间】:2019-12-25 09:33:55
【问题描述】:

场景:

  1. 在没有互联网的情况下打开应用,应用会尝试发出请求,但会失败
  2. 打开互联网连接,然后按重试按钮触发互联网请求
  3. Retrofit & okhttp 总是会给我 HTTP FAILED: java.net.SocketTimeoutException: timeout

从一开始就启用互联网重新启动应用程序将使一切正常,除非我再次关闭它,并且请求失败,从那时起它会给我同样的错误。 我从来没有在 Java 上遇到过这个问题,只是在 Kotlin 上。

private val interceptor: Interceptor =
        object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                var builder = chain.request().newBuilder()
                Prefs.token?.let { token ->
                    builder = builder.addHeader("Authorization", "Bearer $token")
                }
                return chain.proceed(builder.build())
            }
        }

private val httpLoggingInterceptor: HttpLoggingInterceptor by lazy {
    val interceptor = HttpLoggingInterceptor()
    interceptor.level =
            if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
    interceptor
}
private val httpClient: OkHttpClient by lazy {
    OkHttpClient.Builder()
            .addInterceptor(httpLoggingInterceptor)
            .addInterceptor(interceptor)
            .build()
}

val retrofit: Retrofit by lazy {
    Retrofit.Builder()
            .baseUrl("https://api.secret.com/v1/")
            .addConverterFactory(GsonConverterFactory.create(gson))
            .client(httpClient)
            .build()
}

服务类看起来像这样

@GET("something")
fun something(): Call<SomeResponse>

我尝试过使用超时值,无论超时时间如何,我都会得到同样的错误。

为每个请求创建一个新的 http 客户端可以解决问题,但我认为这不是一个好主意。

【问题讨论】:

    标签: kotlin retrofit okhttp


    【解决方案1】:

    您的问题类似于OkHttp Bug。如果您点击链接,您会发现许多可能的解决方案进行了长时间的讨论。

    以下解决方案适用于我的项目:

    1. 更新 OkHttp 至少到 4.3.0。
    2. 设置ping interval,例如1秒
    okHttpClientBuilder.pingInterval(1, TimeUnit.SECONDS)
    

    工作原理

    问题的根源在于 Android 操作系统没有提供任何方法来知道连接不再处于活动状态。所以图书馆连接看起来像活着,但它已经死了。结果,我们在每个请求上都会遇到超时异常。一旦我们设置了 ping,OkHttp 就会开始发送Ping frames,这样如果服务器没有响应库就知道连接已经死了,是时候创建一个新的了。

    不推荐的解决方案,但应该可以工作

    1. 关闭连接池
    okHttpClientBuilder.connectionPool(new ConnectionPool(0, 1, TimeUnit.NANOSECONDS))
    
    1. 使用 Http 1.1
    okHttpClientBuilder.protocols(listOf(Protocol.HTTP_1_1))
    

    在这两种不推荐的解决方案中,您只需停止重复使用已打开的连接,这会使每个请求时间稍微长一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-27
      • 2015-10-07
      • 1970-01-01
      • 2014-04-22
      • 2019-03-25
      • 2015-06-01
      • 1970-01-01
      • 2017-08-27
      相关资源
      最近更新 更多