RxJava 和 Retrofit - 根据服务器响应引发自定义异常

RxJava and Retrofit - Raising custom exceptions depending on server response

我希望 Retrofit 根据服务器响应引发自定义异常。例如在以下结构中:

{
"code":0,
"message":"OK",
"data":{....}
}

如果 code 不是 0,我想为订阅者提出一个例外。如何使用 Retrofit 和 Rx?我更愿意只编写一次此逻辑并将其应用于改造返回的所有可观察量。

I would like to raise an exception for subscribers if code is anything other than 0. How is it possible using Retrofit and Rx?

您可以使用 Observable.flatMap 运算符:

api.request().flatMap(response -> {
    if (response.getCode() != 0) {
        return Observable.error(new Exception("Remote error occurred"));
    }

    return Observable.just(response);
});

I would much prefer to write this logic only once and have it applied to all observables returned by retrofit.

不幸的是,没有办法使用 retrofitrx-java 来完成。您 必须 为每个 retrofit 调用编写上面的代码。您唯一可以做的就是使用 Observable.compose 方法并减少您实际需要编写的样板文件的数量。

api.request().compose(new ResponseTransformer<Response>());

这里是 ResponseTransformer class:

public static class ResponseTransformer<T extends Response> implements Observable.Transformer<T, T> {
    @Override
    public Observable<T> call(final Observable<T> observable) {
        return observable.flatMap(response -> {
            if (response.getCode() != 0) {
                return Observable.error(new Exception("Remote error occurred"));
            }

            return Observable.just(response);
        });
    }
}

更新

好吧,正如我所说,没有办法避免仅使用 retrofitrxjava 的样板代码,但您可以使用 dynamic proxies 解决它(请注意,您不不需要再调用 compose):

final Api api = restAdapter.create(Api.class);

final ClassLoader loader = api.getClass().getClassLoader();
final Class<?>[] interfaces = api.getClass().getInterfaces();

final Api proxy = (Api) Proxy.newProxyInstance(loader, interfaces, new ResponseInvocationHandler(api));

proxy.request().subscribe(response -> {
    System.out.println("Success!");
});

ResponseInvocationHandler class:

public static class ResponseInvocationHandler implements InvocationHandler {
    private final Object target;

    public ResponseInvocationHandler(final Object target) {
        this.target = target;
    }

    @Override
    @SuppressWarnings({"unchecked"})
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        final Object result = method.invoke(target, args);

        if (result instanceof Observable) {
            return Observable.class.cast(result).compose(new ResponseTransformer<>());
        }

        return result;
    }
}

我建议采用不同的方法。

您将需要使用自定义拦截器实现自定义 OkHttp 客户端。

        OkHttpClient client = new OkHttpClient();
        client.interceptors().add(new MyInterceptor());
        mAdapter = new RestAdapter.Builder().setEndpoint(Consts.ENDPOINT).setClient(new OkClient(client))
                .setLogLevel(RestAdapter.LogLevel.BASIC).build();

在您的拦截器中,根据返回的代码,您可以正常进行或抛出异常。

像这样:

public class MyInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());

        if(response.code() == 0) {
            throw new RuntimeException("Something went wrong!");
        }

        return response;
    }
}

1 个自定义 Observable.Operator :

public class YourOperator implements Observable.Operator{  
    public void onNext(Data data){  
        if (data.code != 0 ){  
            //raise your custom Exception  
        }  
    }  
    public void onError(Throwable e){  
        //handler Exception  
    }  
}  

2 个用户喜欢:

api.youRequest()
    .lift(new YourOperator())
    .subscribe(....);