Я получаю это исключение: java.net.ProtocolException: неожиданное завершение потока. W / System.err: в okhttp3.internal.http1.Http1ExchangeCodec $ FixedLengthSource.read (Http1ExchangeCodec.kt: 392)
Я пытаюсь сделать SOAP-запрос.Я не всегда получаю это исключение.Иногда я получаю правильный ответ с веб-сервера.
Я изменил библиотеку синтаксического анализатора с SimpleXML на TikXML, но проблема все еще остается.В методе onResponse я ничего не делаю, но у меня была та же проблема.
Вот как я делаю вызов:
final Call<ResponseEnvelope> consumeWS = RetrofitGenerator
.getConsultarTipoDeDocumentoApi()
.getTiposDeDocumento(this.USERNAME_ENCRYPT, this.USERTOKEN_ENCRYPT,
this.MESSAGEID_ENCRYPT, "close", this.requestEnvelope);
consumeWS.enqueue(new Callback<ResponseEnvelope>() {
@Override
public void onResponse(Call<ResponseEnvelope> call, Response<ResponseEnvelope> response) {
ResponseEnvelope responseEnvelope = new ResponseEnvelope(response.body().getBody());
if(responseEnvelope != null && response.isSuccessful())
dataTipoDeDocumento.setValue(responseEnvelope.getBody().getMtrtipdoccResponse()
.getReturn().getLISTAREGISTROS().getLIST());
}
@Override
public void onFailure(Call<ResponseEnvelope> call, Throwable t) {
t.printStackTrace();
dataTipoDeDocumento.setValue(null);
Вот мой RetrofitGenerator:
private static OkHttpClient.Builder okHttpClient = new OkHttpClient
.Builder();
private static Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create(serializer));
public RetrofitGenerator() {
}
public static <S> S createService(Class<S> serviceClass, String baseUrl) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.level(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = okHttpClient
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(logging)
.build();
Retrofit retrofit = retrofitBuilder.baseUrl(baseUrl).client(client).build();
return retrofit.create(serviceClass);
}
Вот проблема: (Отладка запроса)
override fun read(sink: Buffer, byteCount: Long): Long {
require(byteCount >= 0L) { "byteCount < 0: $byteCount" }
check(!closed) { "closed" }
if (bytesRemaining == 0L) return -1
val read = super.read(sink, minOf(bytesRemaining, byteCount))
if (read == -1L) {
realConnection!!.noNewExchanges() // The server didn't supply the promised content length.
val e = ProtocolException("unexpected end of stream")
responseBodyComplete()
throw e
}
Я заметил, что при сбое есть переменная с именем bytesRemaining, которая получает значение 1 (при неудаче всегда 1).Длина содержимого ответа всегда 933. Я не знаю, что происходит.
Вот мой выпускник:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.app.multired"
minSdkVersion 22
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
dataBinding {
enabled = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.jakewharton:butterknife:10.0.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0'
/* dagger dependency for DI*/
implementation "com.google.dagger:dagger:2.16"
annotationProcessor "com.google.dagger:dagger-compiler:2.16"
compileOnly 'javax.annotation:jsr250-api:1.0'
implementation 'javax.inject:javax.inject:1'
/*Retrofit lib*/
testImplementation 'com.squareup.okhttp3:mockwebserver:4.2.0'
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.0'
//implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.6.1'
/*RxJava lib*/
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation "io.reactivex.rxjava2:rxjava:2.1.8"
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
/* LiveData lib*/
implementation "android.arch.lifecycle:extensions:1.1.1"
implementation "android.arch.lifecycle:runtime:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
implementation 'androidx.recyclerview:recyclerview:1.0.0'
/* Biometric Authentication */
implementation 'androidx.biometric:biometric:1.0.0-alpha03'
implementation 'org.jetbrains:annotations:15.0'
}
Как я решил это:
public abstract class CallbackWithRetry<T> implements Callback<T> {
private static final String TAG = CallbackWithRetry.class.getSimpleName();
@Override
public void onFailure(Call<T> call, Throwable t){
Log.e(TAG, t.getLocalizedMessage());
retry(call);
}
private void retry(Call<T> call){
call.clone().enqueue(this);
}
}
Отредактированный обратный вызов:
final Call<ConsultarTipoDeDocumentoResponseEnvelope> consumeWS = RetrofitGenerator
.getConsultarTipoDeDocumentoApi()
.getTiposDeDocumento(this.USERNAME_ENCRYPT, this.USERTOKEN_ENCRYPT,
this.MESSAGEID_ENCRYPT, this.consultarTipoDeDocumentoRequestEnvelope);
consumeWS.enqueue(new CallbackWithRetry<ConsultarTipoDeDocumentoResponseEnvelope>() {
@Override
public void onResponse(Call<ConsultarTipoDeDocumentoResponseEnvelope> call, Response<ConsultarTipoDeDocumentoResponseEnvelope> response) {
ConsultarTipoDeDocumentoResponseEnvelope consultarTipoDeDocumentoResponseEnvelope = new ConsultarTipoDeDocumentoResponseEnvelope(response.body().getBody());
if(consultarTipoDeDocumentoResponseEnvelope != null && response.isSuccessful())
dataTipoDeDocumento.setValue(consultarTipoDeDocumentoResponseEnvelope.getBody().getMtrtipdoccResponse()
.getReturn().getLISTAREGISTROS().getLIST());
}
@Override
public void onFailure(Call<ConsultarTipoDeDocumentoResponseEnvelope> call, Throwable t) {
super.onFailure(call, t);
}
});
Эта повторная попытка очень полезна, так как Retrofit2 включил переменную вызова в качестве параметра метода onFailure при выполнении вызова очереди.