首页 > 在Android中使用RxJava处理Restful Api格式的错误响应

在Android中使用RxJava处理Restful Api格式的错误响应

最近使用 rxjava 搭配 retrofit 来进行网络访问 API,但不知道该怎样进行错误处理。
因为我的响应格式是这样的:

正确时:

{
  "id": 1,
  "username": "lazyS_WSD_Wd",
  "mobile": "18912345678",
  "email": "",
  "avatar_url": "http://api.xxxx.com/images/default_avatar.png",
  "last_address_id": 1,
  "last_ip": "::1",
  "last_device_type": "android",
  "last_device_id": "99000566712916"
}

而不是这样的:

{
    "status": 200,
    "message": "请求成功",
    "data": {
        "id": 1,
        "username": "lazyS_WSD_Wd",
        "mobile": "18912345678",
        "email": "",
        "avatar_url": "http://api.xxxx.com/images/default_avatar.png",
        "last_address_id": 1,
        "last_ip": "::1",
        "last_device_type": "android",
        "last_device_id": "99000566712916"
    }
}

错误时:

是这样的:

{
  "message": "未找到该地址",
  "status": 404,
}

这时的HTTP响应状态也是404

而不是这样的:

{
    "status": 404,
    "message": "未找到该地址",
    "data": null
}

所以当请求成功,但返回的是用户自定义的错误时,我不能把该自定义的错误解析成指定的错误对象。

以前没有用 rxjava 时,我是这样处理的:

Response<T> response = call.execute();
if (BuildConfig.DEBUG) {
    Logger.json(response.raw().toString());
}
if (response.isSuccess()) {
    result = response.body();
} else {
    responseError = GsonHelper.builderGson().fromJson(response.errorBody().string(), ResponseError.class);
}

请问如果用 rxjava 的话,应该怎样进行处理?先谢谢了!


参考:Retrofit+RxJava 优雅的处理服务器返回异常、错误http://blog.csdn.net/jdsjlzx/...


我的做法是将正常或者异常都封装到一个Result对象中。如果是成功可以通过getResult获取到我们需要的对象;失败时也可以拿到异常码和异常信息。

public class BaseResult<T> implements Serializable {
    private boolean success;//表示是否成功
    private String errCode;
    private String errMsg;
    private T result;//被封装的正确结果对象

然后分两种情况处理异常。一种是直接retrofit2一次调用出现异常;另一种是一次调用拿到结果后又链式调用第二个api时,第一次出现异常。

第一种情况很简单。因为封装的BaseResult可以判断出是否发生异常(success字段)

userService.findUserList()
                .subscribe(userListBaseResult -> {
            if (!userListBaseResult.isSuccess()) {
                fail();//直接进行错误处理
                return;
            }
            List<User> userList = userListBaseResult.getResult();
            //正常流程
        });
        

第二种情况。可以选择链式,因为美观;也可以选择两次分开调用。如果两次分开调用的话,第一次的异常处理同上。如果选择链式:

//这里先根据id查到用户后更新用户信息
userService.findUser(5)
                .flatMap(userBaseResult -> {
                    if (!userBaseResult.isSuccess()) {
                        //封装自定义异常,重新传递下去
                        return Observable.error(new BusinessRuntimeException(userBaseResult.getErrCode()));
                    } else {
                        User user = userBaseResult.getResult();
                        user.setAddress("XXX");
                        return userService.updateUser(user.getId(), user);
                    }
                })
                .subscribe(updateResult -> {
                    //正常走到这里
                    if (!updateResult.isSuccess()) {
                        //异常
                    } else {
                        //正常处理
                    }
                }, exception -> {
                    //findUser发生异常走到这里
                    if (exception instanceof BusinessRuntimeException) {
                        //异常处理
                    }
                });

我通过查看 RxJavaCallAdapterFactory 这个类的代码,自己解决了这个问题。
我发现当使用RxJava创建observables时,可以有三种不同的返回类型

我定义了一个类 ResponseError来接收错误消息的响应。

public class ResponseError {

    public int status;
    public String message;

    // getter 和 setter 方法略

    // 主要是这个方法
    public static ResponseError handle(Throwable throwable) {
        ResponseError error = null;
        if (throwable instanceof HttpException) {
            HttpException exception = (HttpException) throwable;
            try {
                error = new Gson().fromJson(exception.response().errorBody().string(),
                                ResponseError.class);
            } catch (Exception e) {
                if (e instanceof JsonParseException) {
                    error = new ResponseError(HTTP_SERVER_ERROR, "服务器出错");
                } else {
                    error = new ResponseError(HTTP_UNKNOWN_ERROR, "未知错误");
                }
            }
        } else {
            error = new ResponseError(HTTP_UNKNOWN_ERROR, "未知错误");
        }
        if (BuildConfig.DEBUG) {
            throwable.printStackTrace();
        }

        return error;
    }
}

然后再定义了一个Action:

public abstract class ErrorAction implements Action1<Throwable> {

    @Override
    public void call(Throwable throwable) {
        ResponseError error = ResponseError.handle(throwable);
        call(error);
    }

    public abstract void call(ResponseError error);
}

这样,在使用 Rxjava 链式操作的时候就可以这样了

mRestApiClient.accountService()
        .login(username, password)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<List<Business>>() {
            @Override
            public void call(List<Business> businesses) {
                // do something
            }
        }, new ErrorAction() {
            @Override
            public void call(ResponseError error) {
                // do something
            }
        });

记录在此,希望能帮到后面的朋友!


public abstract class BaseModel {
    public int status;
    public String message;
}

public class XX extends BaseModel {
    //
}
XX xx = new XX();
xx.status = 404;
xx.message = "Not Found";
Observable
        .just(xx)
        .flatMap(x -> {
            if (xx.status == 200) {
                return Observable.just(x);
            } else {
                return Observable.error(new Exception(xx.message));
            }
        })
        .subscribe(new Subscriber<XX>() {
            @Override
            public void onCompleted() {
            }
            
            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }
            
            @Override
            public void onNext(XX xx) {
                System.out.println(xx);
                //要么就不要上面的flatMap,直接在这判断处理。
            }
        });
【热门文章】
【热门文章】