【问题标题】:Retrofit error handling改造错误处理
【发布时间】:2014-12-28 14:14:19
【问题描述】:

我将我的 Retrofit 代码封装在一个类中,如下所示。如果从我发布的代码中不清楚,它正在与带有 OAuth 的宁静服务进行交互。

什么是进行错误处理的好方法? REST 服务器以 json 格式返回错误消息。我想通过从我的班级抛出一些异常来对该消息采取行动。我正在尝试做类似下面的事情。但这是好的设计吗?混合回调和异常抛出一个好主意吗?有没有更好的办法?

通过下面的方法,我可以从我的自定义异常中获取 i18l 消息并将它们敬酒给用户。

public class RestClient implements IRestClient {
    private IRestAPI api;

    /**
     *
     * @param accessToken
     */
    public RestClient(final String accessToken)
    {
        RequestInterceptor requestInterceptor = new RequestInterceptor()
        {
            @Override
            public void intercept(RequestFacade request) {
                request.addHeader("Authorization", "Bearer " + accessToken);
            }
        };

        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(Config.ENDPOINT)
                .setRequestInterceptor(requestInterceptor)
                .build();
        api = restAdapter.create(IRestAPI.class);
    }

    @Override
    public void requestSomething(final Callback callback) {
        api.getSomething(new Callback<Something>() {
            @Override
            public void success(Something something, Response response) {
                callback.success(something, response);
            }

            @Override
            public void failure(RetrofitError error) {
                if(error.getMessage().getId().euqals(ACCESS_TOKEN_EXPIRED))
                {
                    throw new AccessTokenExpired();
                }
                else if(error.getMessage().getId().euqals(USER_NOT_FOUND))
                {
                    throw new UsernamePasswordNotFound();
                }
                else // something else happened...
                {
                    throw error;
                }
            }
        });
    }

    @Override
    public void deleteSomething(final Callback callback) {
        api.deleteSomething(new Callback<Something>() {
            @Override
            public void success(Something something, Response response) {
                callback.success(something, response);
            }

            @Override
            public void failure(RetrofitError error) {
                if(error.getMessage().getId().euqals(SOMETHING_NOT_FOUND))
                {
                    ...
                    ...
                    Different exceptions
                }
                ...
            }
        });
    }

}

当然,我必须创建自己的回调接口,只有一个成功方法。

【问题讨论】:

标签: java android error-handling retrofit


【解决方案1】:

当您构建RestAdapter 时,您可以提供映射到您的自定义异常的error handler,它会绕过任何4xx/5xx 上的Callback&lt;T&gt; 中对failure 的调用。作为一个非常人为的例子:

public class Scratch {
    public static void main(String[] args) {
        Endpoints e = new RestAdapter.Builder()
                .setEndpoint("http://google.com")
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setErrorHandler(new ErrorHandler() {
                    @Override
                    public Throwable handleError(RetrofitError cause) {
                        switch (cause.getResponse().getStatus()) {
                            case 400:
                                /* Handle the expected body format */
                                cause.getBody();
                                throw new RuntimeException("Bad Request");
                            default:
                                /* Things and stuff */
                                throw new RuntimeException("");
                        }
                    }
                })
                .build()
                .create(Endpoints.class);

        e.getGoogle(new Callback<Response>() {
            @Override
            public void success(Response response, Response response2) {
                System.out.println("Got it");
            }

            @Override
            public void failure(RetrofitError error) {
                System.err.println("This won't ever be seen due to the error handler.");
            }
        });
    }

    private static interface Endpoints {
        @GET("/foo/bar")
        void getGoogle(Callback<Response> callback);
    }
}

edit:但是,这样做可能会牺牲一个重要的原因,即为什么要使用Callback 接口。如果这是您需要的常见用途,则使用同步调用并返回您的对象类型可能更有意义。我不完全知道你用什么来说这是必要的,但似乎它可能更合适。

【讨论】:

  • 是的,但我想要不同的方法有不同的例外......或者至少我认为我愿意。我不太确定这种方法。假设我有一个 createSomething 方法。这可能会引发 AlreadyExistsException。如果我有一个 deleteSomething 方法,它可能会抛出 SomethingNotFoundException... 有意义吗?
  • 我真的不认为你这样做,至少在这个级别上。您使用的任何 HTTP 服务都应使用标准错误代码(或有一些标准来告诉您请求失败的原因)。因此,在我的回答中的switch 示例中,并使用您的评论作为模板,您可以将409 映射到您的ConflictException,将404 映射到您的NotFoundException 作为状态码:异常映射。当你调用一个给出 4xx/5xx 的东西时——不管它是什么,你都会得到一个标准异常。
  • 当然,这样做的不利方面是,如果您希望这是一种常见的事情 - 也许使用Callback 接口不适合您使用。
  • 好吧,我可能会得到 404,但找不到用户和文章。但我想要不同的错误信息。此外,这不仅仅是关于 http 错误代码...尝试删除用户或文章也会导致针对不同情况的不同代码
  • @MikeWallaceDev 这真的取决于你在做什么。如果您返回一个Observable&lt;T&gt;,那么该逻辑在您的SubscriberonError 方法中完成,如果您正在执行回调我不确定(我没有真正使用过这些,我使用Rx 代替),如果您正在执行标准 Response 或具体类,那么您将包装 HTTP 调用(如果合适)。例如try { myImplSyncronous.getResource(); } catch (RetrofitError e) { /*handle*/}
猜你喜欢
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
  • 2017-06-30
  • 2016-05-03
  • 1970-01-01
  • 2015-10-10
  • 2016-12-20
  • 1970-01-01
相关资源
最近更新 更多