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.
不幸的是,没有办法使用 retrofit
和 rx-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);
});
}
}
更新
好吧,正如我所说,没有办法避免仅使用 retrofit
和 rxjava
的样板代码,但您可以使用 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(....);
我希望 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.
不幸的是,没有办法使用 retrofit
和 rx-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);
});
}
}
更新
好吧,正如我所说,没有办法避免仅使用 retrofit
和 rxjava
的样板代码,但您可以使用 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(....);