Retrofit 2.0 + RxJava +错误的JSON正文

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (17)

我对RxJava和Retrofit很新,并且正在尝试使用它编写我的API调用。所有的API调用都返回一个错误的JSON体,它的格式为:

{"errors":[{"code":100, "message":"Login/Password not valid", "arguments":null}]}

目前我的登录API调用代码(其他人也是类似的)是,

mConnect.login(id, password)
        .subscribe(new Subscriber<Token>() {
            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError(): " + e);
                if (e instanceof HttpException) {
                  // dump e.response().errorBody()
                }
            }

            @Override
            public void onNext(Token token) {
                Log.d(TAG, "onNext(): " + token);
            }
        });

当我在onError()出现错误时,我想自动将错误主体中的JSON解码为POJO,并使用它。有没有办法在一个地方为所有其他API调用执行此操作。任何帮助表示赞赏。

提问于
用户回答回答于

反序列化也可能是一个问题。您可以使用改造转换器对其进行反序列化(或者自己做)。

我的解决方案为murki添加了一点:

<T> Observable.Transformer<T, T> parseHttpErrors() {
        return new Observable.Transformer<T, T>() {
            @Override
            public Observable<T> call(Observable<T> observable) {
                return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
                    @Override
                    public Observable<? extends T> call(Throwable throwable) {
                        if ( throwable instanceof HttpException ) {
                            Retrofit retrofit = new Retrofit.Builder()
                                    .baseUrl(SERVER_URL) // write your url here
                                    .addConverterFactory(GsonConverterFactory.create())
                                    .build();
                            Converter<ResponseBody, Error> errorConverter =
                                    retrofit.responseBodyConverter(Error.class, new Annotation[0]);
                            // Convert the error body into our Error type.
                            try {
                                Error error = errorConverter.convert(((HttpException) throwable).response().errorBody());
                                // Here you have two options, one is report this pojo back as error (onError() will be called),
                                return Observable.error(new Throwable(error.getMessage()));
                            }
                            catch (Exception e2) {
                                return Observable.error(new Throwable());
                            }

                        }
                        // if not the kind we're interested in, then just report the same error to onError()
                        return Observable.error(throwable);
                    }
                });
            }
        };
    }

然后在onError()中,

@Override
public void onError(Throwable e) {
    progressBar.setVisibility(View.GONE); // optional 
    if ( !TextUtils.isEmpty(e.getMessage()) ) {
            // show error as you like 
            return;
    }
    // show a default error if you wish
}
用户回答回答于

我会建议使用可重用的TransformeronErrorResumeNext运算符来封装您的逻辑。它看起来像这样:

<T> Observable.Transformer<T, T> parseHttpErrors() {
    return new Observable.Transformer<T, T>() {
        @Override
        public Observable<T> call(Observable<T> observable) {
            return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
                @Override
                public Observable<? extends T> call(Throwable throwable) {
                    if (throwable instanceof HttpException) {
                        HttpErrorPojo errorPojo = // deserialize throwable.response().errorBody();

                        // Here you have two options, one is report this pojo back as error (onError() will be called),
                        return Observable.error(errorPojo); // in this case HttpErrorPojo would need to inherit from Throwable

                        // or report this pojo back as part of onNext()
                        return Observable.just(errorPojo); //in this case HttpErrorPojo would need to inherit from <T>
                    }
                    // if not the kind we're interested in, then just report the same error to onError()
                    return Observable.error(throwable);
                }
            });
        }
    };
}

注意代码中的注释,因为您必须决定是否要报告解析的响应onError()或onNext()。

然后你可以在你的API调用的任何地方使用这个变换器,例如:

mConnect.login(id, password)
        .compose(this.<Token>parseHttpErrors()) // <-- HERE
        .subscribe(new Subscriber<Token>() {
            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError(): " + e);
                if (e instanceof HttpErrorPojo) {
                  // this will be called if errorPojo was reported via Observable.error()
                }
            }

            @Override
            public void onNext(Token token) {
                Log.d(TAG, "onNext(): " + token);
                if (token instanceof HttpErrorPojo) {
                  // this will be called if errorPojo was reported via Observable.just()
                }
            }
        });

扫码关注云+社区