СБОЙ HTTP: исключение java.io.IOException: исключение неожиданного завершения потока при выполнении запроса https

#android #retrofit #okhttp #okhttp3

#Android #модернизация #okhttp

Вопрос:

Ранее мы использовали http API, а теперь перешли на https, с тем же кодом мы сталкиваемся с исключением HTTP FAILED: java.io.IOException: неожиданный конец потока (это для некоторого устройства и для некоторых сетевых вызовов). Мы используем OkHttp и модифицируем из приложения Android. Ниже приведен наш код

 @Provides
    @ApplicationScope
    OkHttpClient provideOkHttpClientV2(
            HttpLoggingInterceptor logging,
            Interceptor headerInterceptor) {
    OkHttpClient.Builder builder = new OkHttpClient.Builder();

    //Removed custom timeout units
    return builder.addInterceptor(headerInterceptor)
            .addInterceptor(logging)
            .retryOnConnectionFailure(true)
            .readTimeout(100, TimeUnit.SECONDS)
            .connectTimeout(100, TimeUnit.SECONDS)
            .build();

 }

@Provides
@ApplicationScope
Interceptor provideRetrofitHeaderV2(final SharedPreferencesUtil sharedPreferencesUtil) {
    return new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original = chain.request();

            Request.Builder builder = original.newBuilder();
            builder.header("Content-Type", "application/json")
                    .method(original.method(), original.body());
            if (sharedPreferencesUtil != null) {
                if (sharedPreferencesUtil.isLogin()) {

                    String loginToken = sharedPreferencesUtil.getLoginToken();
                    builder.addHeader("Authorization", "Bearer "   loginToken);
                }
            }

            builder.addHeader("Connection", "close");

            Request request = builder.build();
            return chain.proceed(request);
        }
    };
}

@Provides
@ApplicationScope
HttpLoggingInterceptor provideLoggingInterceptorV2() {
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    if (BuildConfig.DEBUG) {
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    } else {
        logging.setLevel(HttpLoggingInterceptor.Level.NONE);
    }
    return logging;
}

@Provides
@ApplicationScope
Retrofit provideRetrofitV2(OkHttpClient okHttpClient) {
    return new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .baseUrl(BuildConfig.BASE_URL)
            .client(okHttpClient)
            .build();
}```
  

То, что мы уже пробовали:

  • Добавить заголовок с addHeader("Connection", "close")
  • Добавьте пул соединений, чтобы ограничить идеальные соединения
  • увеличьте время ожидания

Любая помощь будет оценена, мы сталкиваемся с этой проблемой уже довольно давно.

Комментарии:

1. Похоже на проблему с OkHttp github.com/square/okhttp/issues/2738

2. Уже проверено, что большинство ответов не работают с нашим случаем.

3. @Asheesh Я запускаю с реальным устройством, и все будет в порядке.

Ответ №1:

У меня только что это произошло, и я нашел обходной путь. Это было вызвано использованием HttpLoggingInterceptor. При отладке кода okhttp я обнаружил, что он выдает эту ошибку, потому что длина тела не соответствует заголовку content length в ответе. Если он получает заголовок содержимого, он использует FixedLengthSource, и это вызовет ошибку «неожиданный конец потока» при чтении. Вы можете увидеть это в исходном коде https://github.com/square/okhttp/blob/okhttp_3.9.x/okhttp/src/main/java/okhttp3/internal/http1/Http1Codec.java Метод openResponseBody

В качестве обходного пути я добавил в свой конструктор интерпретатор ответа, который удаляет заголовок content-length, что заставляет его использовать UnknownLengthSource.

  private static final Interceptor REWRITE_CONTENT_LENGTH_INTERCEPTOR = new Interceptor() {
    @Override public Response intercept(Interceptor.Chain chain) throws IOException {
      Response originalResponse = chain.proceed(chain.request());
      return originalResponse.newBuilder().removeHeader("Content-Length")
              .build();
    }
  };