使用Retrofit和RxJava/RxAndroid如何处理响应错误?

3

我遇到了一些问题,不知道如何处理使用Retrofit和RxAndroid出现的响应错误。如果出现网络错误之类的情况会调用onError(),但我需要获得响应以检查是否存在身份验证错误。相反,我得到了一个空字符串的token,但无法找出原因。该怎么做才能解决这个问题?

这是我目前的RxAndroid调用。

    Client.getInstance().getService()
            .getToken(usernameET.getText().toString(), passwordET.getText().toString())
            .subscribe(new Subscriber<SiteInfo>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {
                    e.printStackTrace();
                }

                @Override
                public void onNext(SiteInfo siteInfo) {
                    Log.d(TAG, "onNext "+ token.toString());
                }
            });

这是我的Retrofit服务。
@GET("my_url_here")
Observable<Token> getToken(
        @Query("username") String username,
        @Query("password") String password
);

这是我的当前restadapter。
RestAdapter restAdapter = new RestAdapter.Builder()
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .setEndpoint(BASE_URL)
            .build();

service = restAdapter.create(MyService.class);

这是我的 Token 类。

public class Token {
    private String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public String toString() {
        return token;
    }
}

我该如何处理这个问题呢?它可以在RxAndroid部分完成吗?还是需要在我的RestClient中添加一些内容,或者完全需要其他东西?
谢谢。
07-01 06:38:04.562    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ ---> HTTP GET my_website_here
07-01 06:38:04.562    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ ---> END HTTP (no body)
07-01 06:38:04.610    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ <--- HTTP 200 my_website_here (48ms)
07-01 06:38:04.610    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ : HTTP/1.1 200 OK

很不幸,服务器没有提供状态码。我收到的响应是 {"error":"The username was not found in the database","stacktrace":null,"debuginfo":null,"reproductionlink":null} - Radther
啊,是的,我明白你的意思。服务器可能会给我一个 200 状态码,但这并没有什么帮助。 - Radther
我认为他的意思是服务器发送了200给他。但响应包含错误字符串。在这种情况下,你真的不能责怪Retrofit。请向模块所有者请求在响应中发送错误代码,如500等,或通过解析JSON并检查error!= null来自己处理它。 - Ramandeep Nanda
@Radther 在 Retrofit 中启用日志并发布服务器的完整响应,而不仅仅是响应体。 - eleven
我已经添加了我收到的响应。 - Radther
显示剩余3条评论
2个回答

3

我找到了一个解决方案

首先,我扩展了我的Token对象,增加了一个错误属性。

public class Token {

    private String token;
    private String error;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

    @Override
    public String toString() {
        return token;
    }
}

然后我在我的RxJava链中添加了一个操作符,它可以检查错误字段是否不为null。如果有错误,则抛出一个自定义异常,调用订阅者的onError,使我能够处理它。

if (token.getError() != null) {
    throw OnErrorThrowable.from(new UserAuthenticationException(token.getError()));
    }

如果出现错误,抛出自定义异常,并调用订阅者的 onError 方法以便我处理。

if (e instanceof OnErrorThrowable){
    if (e.getCause() instanceof UserAuthenticationException){
        Log.d(TAG, "onError "+e.getCause().getMessage());
    }
    e.getCause().printStackTrace();
}

你能告诉我们在 RxJava 链中添加的运算符是什么吗?我正在做和你一样的事情,我想在某个地方因式分解错误检查。我目前正在使用 .flatMap(...),但这不是很“美观”。 - mithrop
@mithrop 我相信我刚刚使用了一个map操作符,如果出现错误,我会抛出异常,否则,我只是返回对象。所以在这种情况下,是map<Token, Token>。 - Radther

1

虽然有点晚了,但如果有人来到这里,Retrofit 2将HttpException的实例传递给onError回调函数,每当从服务器返回一个错误代码超出[200,300)区间的请求时...

throwable -> {
    if(throwable instanceof HttpException){
        switch(((HttpException)throwable).code()){
            // your error handling logic 
        }
    }
}

您还可以从此对象中检索整个响应。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接