在主题发射上调用另一个Retrofit调用

时间:2016-11-23 11:12:53

标签: request rx-java retrofit2 ioexception subject

我有以下课程:

public class SessionStore {
    Subject<Session, Session> subject;

    public SessionStore() {
       subject = new SerializedSubject<>(BehaviorSubject.create(new Session());
    }

    public void set(Session session) {
        subject.onNext(session);
    }

    public Observable<UserSession> observe() {
        return subject.distinctUntilChanged();
    }
}

在活动中,我观察会话并对每次更改执行网络操作:

private Subscription init() {
    return sessionStore
            .observe()
            .flatMap(new Func1<Session, Observable<Object>>() {
                @Override
                public Observable<Object> call(Session session) {
                    return (session.isValid() 
                       ? retrofitService.getThingForValid()
                       : retrofitService.getThingForInalid())
                       .subscribeOn(Schedulers.io());
                }
            })
            .subscribe(...);
}

现在我有一个Okhttp请求拦截器,当网络响应为非200代码时,我将会话实例从有效设置为无效。

这就是:

  1. 在初始订阅会话存储时,getThingForValid()已执行,但失败。
  2. OkHttp拦截失败并设置新会话。
  3. 会话存储会发出一个新的,现在无效的会话。
  4. 新发射执行getThingForInvalid()方法。
  5. 重要的是要知道这个执行发生在上一次Retrofit调用的中间。这是因为OkHttp客户端被Retrofit包装,所有拦截器都在Retrofit返回之前执行。

    考虑到这一点,你意识到第二个电话正在由Retrofit执行和处理,而第一个电话尚未完成。

    1. 当第一个调用完成时,它会抛出HttpException,因为响应是非200代码。
    2. xception杀死rx流,并随之进行第二次呼叫。
    3. 我试图在流中忽略此异常,但第二次调用仍被Retrofit取消。

      你有什么想法让我的概念有用吗?

1 个答案:

答案 0 :(得分:0)

如果您在令牌过期时收到响应代码401: 您需要将Authenticator添加到OkHttpClient.Builder

builder.authenticator(new Authenticator() {
            @Override
            public Request authenticate(Route route, Response response) throws IOException {
                final LoginResponse newLoginResponse = refreshTokenClient.refreshToken();
                //save new token locally, if needed
                return response
                        .request()
                        .newBuilder()
                        .removeHeader("Api-Auth-Token") // removing old header
                        .addHeader("Api-Auth-Token", newLoginResponse.getAuthToken())
                        .build();
            }
        });

,其中

public interface RefreshTokenService {

   @PUT("/api/v1/tokens")
   LoginResponse refreshToken();

 }

但请注意:每次响应代码为Authenticator时,此401都会运行。