最近使用 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时,可以有三种不同的返回类型
Observable<Foo>
Observable<Response<Foo>>
Observable<Result<Foo>>
而Observable<Foo>这种返回类型的OnErrorAction里的throwable参数是HttpException这种类型的,这个HttpException里有 Response 对象,自然的,就可以拿到 errorBody 来进行我所想要的处理了。
我定义了一个类 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,直接在这判断处理。
}
});