使用rxjava2时Retrofit2未经身份验证的401错误 [英] Retrofit2 Unauthenticated 401 error when using rxjava2

查看:1276
本文介绍了使用rxjava2时Retrofit2未经身份验证的401错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自从我集成了RxJava2以来,我在返回 Observable 的所有改造调用中都收到401未经身份验证的错误,因此我使用的是基本身份验证,我知道错误是由于此导致的,但是为什么呢?适用于调试但不能发布.

Ever since i'v integrated RxJava2 , i am receiving 401 unauthenticated error in all retrofit calls that return Observable , i'm using basic authentication and i know error is due to it , but why it works on debug but not release.

我认为Retrofit2的rxjava适配器的配置有问题

In my opinion something is wrong with the configuration for rxjava adapters of retrofit2

com.jakewharton.retrofit2.adapter.rxjava2.HttpException: HTTP 401 Unauthorized
01-22 19:24:14.872 11502-11502/? W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:54)
01-22 19:24:14.872 11502-11502/? W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:37)
01-22 19:24:14.872 11502-11502/? W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.CallObservable.subscribeActual(CallObservable.java:43)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10514)
01-22 19:24:14.872 11502-11502/? W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10514)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnLifecycle.subscribeActual(ObservableDoOnLifecycle.java:33)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10514)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10514)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.internal.operators.observable.ObservableObserveOn.subscribeActual(ObservableObserveOn.java:44)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10514)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.Scheduler$1.run(Scheduler.java:134)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
01-22 19:24:14.872 11502-11502/? W/System.err:     at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
01-22 19:24:14.872 11502-11502/? W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
01-22 19:24:14.872 11502-11502/? W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
01-22 19:24:14.872 11502-11502/? W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
01-22 19:24:14.872 11502-11502/? W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1115)
01-22 19:24:14.872 11502-11502/? W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:590)
01-22 19:24:14.872 11502-11502/? W/System.err:     at java.lang.Thread.run(Thread.java:818)

Build.gradle:

::project::
apply plugin: 'com.android.application' //or apply plugin: 'java'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.jakewharton.hugo'
apply plugin: 'android-apt'
def AAVersion = '4.1.0'

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.2'

    defaultConfig {
        applicationId "com.jutt.example1"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 4
        versionName "1.0"
        multiDexEnabled false
    }
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources false
            zipAlignEnabled true
            //debuggable false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }

}

apt {
    arguments {
        // you should set your package name here if you are using different application IDs
        // resourcePackageName "your.package.name"

        // You can set optional annotation processing options here, like these commented options:
        // logLevel 'INFO'
        // logFile '/var/log/aa.log'
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    apt "org.androidannotations:androidannotations:$AAVersion"
    compile "org.androidannotations:androidannotations-api:$AAVersion"
    // Retrofit & OkHttp
    // Because RxAndroid releases are few and far between, it is recommended you also
// explicitly depend on RxJava's latest version for bug fixes and new features.

// If you want to bind to Android-specific lifecycles

// If you want pre-written Activities and Fragments you can subclass as providers
    compile 'com.android.support:support-v4:25.1.0'
    compile 'com.android.support:multidex:1.0.1'
    compile 'com.android.support:appcompat-v7:25.1.0'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    //compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.4.2'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.afollestad.material-dialogs:core:0.9.0.2'
    compile 'com.github.ganfra:material-spinner:1.1.1'
    compile 'com.android.support:design:25.1.0'
    compile 'org.apache.commons:commons-lang3:3.4'
    compile 'com.wdullaer:materialdatetimepicker:2.5.0'
    //compile 'io.reactivex:rxandroid:1.2.1'
    //compile 'io.reactivex:rxjava:1.1.6'
    compile 'io.reactivex.rxjava2:rxjava:2.0.2'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.trello.rxlifecycle2:rxlifecycle:2.0.1'
}

::app::

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0-beta2'
        classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
        classpath 'me.tatarka:gradle-retrolambda:3.3.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        // replace with the current version of the android-apt plugin
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}


allprojects {
    repositories {
        jcenter()
        mavenCentral()
        mavenLocal()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

progaurd:

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/zulqurnainjutt/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

-optimizationpasses 5
#-allowaccessmodification
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose

#your package path where your gson models are stored
-keep class com.jutt.example1.model.** { *; }

# Retrofit, OkHttp, Gson
-keepattributes *Annotation*
-keepattributes Signature
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**
-dontwarn rx.**
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepclasseswithmembers class * {
    @retrofit.http.* <methods>;
}
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**

# Rxjava-promises

-keep class com.darylteo.rx.** { *; }

-dontwarn com.darylteo.rx.**

# RxJava 0.21

-keep class rx.schedulers.Schedulers {
    public static <methods>;
}
-keep class rx.schedulers.ImmediateScheduler {
    public <methods>;
}
-keep class rx.schedulers.TestScheduler {
    public <methods>;
}
-keep class rx.schedulers.Schedulers {
    public static ** test();
}

## Retrolambda specific rules ##

# as per official recommendation: https://github.com/evant/gradle-retrolambda#proguard
-dontwarn java.lang.invoke.*

-keep class rx.internal.util.unsafe.** {
    *;
}

错误所在的基本身份验证代码:

class Factory {
        private static SERVERAPI service;

        public static SERVERAPI getIstance(Context context, String base_url,String username,String password) {
            if (service == null) {

                OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
                builder.readTimeout(2, TimeUnit.MINUTES);
                builder.connectTimeout(2, TimeUnit.MINUTES);
                builder.writeTimeout(2, TimeUnit.MINUTES);

                //builder.certificatePinner(new CertificatePinner.Builder().add("*.androidadvance.com", "sha256/RqzElicVPA6LkKm9HblOvNOUqWmD+4zNXcRb+WjcaAE=")
                //    .add("*.xxxxxx.com", "sha256/8Rw90Ej3Ttt8RRkrg+WYDS9n7IS03bk5bjP/UXPtaY8=")
                //    .add("*.xxxxxxx.com", "sha256/Ko8tivDrEjiY90yGasP6ZpBU4jwXvHqVvQI0GS3GNdA=")
                //    .add("*.xxxxxxx.com", "sha256/VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=")
                //    .build());


                if (BuildConfig.DEBUG) {
                    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
                    interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
                    builder.addInterceptor(interceptor);

                    if(username != null) {
                        if(password == null){
                            password = "";
                        }
                        final String credential = Credentials.basic(username, password);
                        builder.addInterceptor(chain -> {
                            Request original = chain.request();

                            Request.Builder requestBuilder = original.newBuilder()
                                    .header("Authorization", credential);
                            requestBuilder.header("Accept", "application/json");
                            requestBuilder.method(original.method(), original.body());

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

                int cacheSize = 10 * 1024 * 1024; // 10 MiB
                Cache cache = new Cache(context.getCacheDir(), cacheSize);
                builder.cache(cache);
                Retrofit retrofit;
                //RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
                if (base_url == null) {
                    retrofit = new Retrofit.Builder()
                            .client(builder.build())
                            .addConverterFactory(GsonConverterFactory.create())
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                            .baseUrl(BASE_URL).build();
                } else {
                    retrofit = new Retrofit.Builder()
                            .client(builder.build())
                            .addConverterFactory(GsonConverterFactory.create())
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                            .baseUrl(base_url).build();
                }
                service = retrofit.create(SERVERAPI.class);
                return service;
            } else {
                return service;
            }
        }

        public static SERVERAPI getIstance(Context context) {
            return getIstance(context, null,null,null);
        }

        public static SERVERAPI getInstanceWithAuthBasic(Context context,String username,String password){ // im using this method
            return getIstance(context, null,username,password);
        }

        public static SERVERAPI getInstanceWithAuthBasic(Context context,String base_url,String username,String password){
            return getIstance(context, base_url,username,password);
        }
    }

我正尝试解决此问题超过2周,现在这是我在 rxjava问题页面,而我之前与同一问题相关的问题是

I'm trying to resolve this issue for over a 2 week now here is my post at rxjava issue page and my previous same issue related question is here , how can i resolve this issue and make it working

推荐答案

您的异常发生在您未在此处列出的类中.

Your exception happens in the class which you had not listed here.

无论如何,您需要分析onError处理程序使用的Exception类型.使用Retrofit2 Observables(无论rxjava版本如何)处理有效的HTTP错误响应非常容易.

Anyway, you need to analyze the type of Exception which comes to onError handler. Handling of valid HTTP error responses with Retrofit2 Observables in (regardless of rxjava version) is quite easy.

首先,您需要知道的是,返回Obsrvable<MyObject>retrofit api方法将仅通过onNext 2xx HTTP响应进行传播.所有其他响应将在onError处理程序中发送.这是如何处理它的代码(Kotlin示例,只是为了给出和想法.Java会这样):

First you need to know is that retrofit api method returning Obsrvable<MyObject> will propagate with onNext only 2xx HTTP responses. All other responses will be sent within onError handler. Here is the code how to handle it (Kotlin example, just to give and idea. Java will ):

retrofitApiService.suggest(
        token,
        query).subscribe ({ suggestions ->
    log.info("Got result: {}", suggestions)
}, { error ->
    //

    if(error is HttpException) {
        if(error.code() == 401) {
            // We've got HTTP 401 Unauthorized
        } else {

            log.error("HTTP Error: {} {}, {}",
                    error.response().code(),
                    error.response().message(),
                    error.response().errorBody().toString())
        }

    } else {
        // something really wrong happened
        // e.g.: invalid json or something else
        log.error("Error: ${error.message}", error)
    }
})

如果希望将所有响应发送到onNext,则应使用Observable<ResponseBody>.在这种情况下,所有有效的HTTP响应都将以onNext结尾,并且所有代码异常都将发送到onError.

If you wish to get all responses into onNext, then you should use Observable<ResponseBody>. In that case all valid HTTP responses will end up in onNext, and all your code exceptions will be sent to onError.

这篇关于使用rxjava2时Retrofit2未经身份验证的401错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆