Retrofit请求数据对错误以及网络异常的处理

2023-10-27

异常处理

Retrofit本身会抛出HttpException,Gson解析会抛出解析异常,
此外我们还应该处理与服务器约定好的“异常”,即上一篇提到的返回数据中result字段值不会0的情况

这里要先解决一个问题,就是Gson构建的对象,通过注解定义key名,以变量的类型定value的类型,
但如果同样的key在不同情况下属于不同的数据类型,就会出问题。

假如服务器返回格式是

{
    "result":"结果代号,0表示成功",
    "msg":"成功返回时是消息数据列表,失败时是异常消息文本"
}

么msg究竟应该定义为String,还是一个List呢

我找到的解决方法就是:
注册一个自定义的转换类GsonResponseBodyConverter
先用一个只含result变量的Model类去解析获得result值
如果失败,则用msg是String的Model类再去解析msg值,然后组成一个ResultException
如果成功,则按照原本的Model类解析

代码如下:

class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final Type type;

    GsonResponseBodyConverter(Gson gson, Type type) {
        this.gson = gson;
        this.type = type;
    }

    @Override
    public T convert(ResponseBody value) throws IOException{
        String response = value.string();
        try {
            Log.d("Network", "response>>" + response);
            //ResultResponse 只解析result字段
            ResultResponse resultResponse = gson.fromJson(response, ResultResponse.class);
            if (resultResponse.getResult() == 0){
                //result==0表示成功返回,继续用本来的Model类解析
                return gson.fromJson(response, type);
            } else {
                //ErrResponse 将msg解析为异常消息文本
                ErrResponse errResponse = gson.fromJson(response, ErrResponse.class);
                throw new ResultException(resultResponse.getResult(), errResponse.getMsg());
            }
        } finally {
        }
    }
}

这个类用于捕获服务器约定的错误类型

public class ResultException extends RuntimeException {

    private int errCode = 0;

    public ResultException(int errCode, String msg) {
        super(msg);
        this.errCode = errCode;
    }

    public int getErrCode() {
        return errCode;
    }
}

拷贝原生的ResponseConverterFactory,将GsonResponseBodyConverter替换为前面我们自定义的

public class ResponseConverterFactory extends Converter.Factory {

    ...
    ...

    @Override
    public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) {
        return new GsonResponseBodyConverter<>(gson, type);
    }

    @Override
    public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
        return new GsonRequestBodyConverter<>(gson, type);
    }

}

然后在构建Retrofit时注册这个工厂类

Retrofit = new Retrofit.Builder()
                .baseUrl(API_SERVER + "/")
                //注册自定义的工厂类
                .addConverterFactory(ResponseConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(mOkHttpClient)
                .build();

这样就完成了Retrofit也可以抛出服务器约定异常

然后就是具体的处理:

public abstract class AbsAPICallback<T> extends Subscriber<T> {

    //对应HTTP的状态码
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;
    //出错提示
    private final String networkMsg;
    private final String parseMsg;
    private final String unknownMsg;

    protected AbsAPICallback(String networkMsg, String parseMsg, String unknownMsg) {
        this.networkMsg = networkMsg;
        this.parseMsg = parseMsg;
        this.unknownMsg = unknownMsg;
    }


    @Override
    public void onError(Throwable e) {
        Throwable throwable = e;
        //获取最根源的异常
        while(throwable.getCause() != null){
            e = throwable;
            throwable = throwable.getCause();
        }

        ApiException ex;
        if (e instanceof HttpException){             //HTTP错误
            HttpException httpException = (HttpException) e;
            ex = new ApiException(e, httpException.code());
            switch(httpException.code()){
                case UNAUTHORIZED:
                case FORBIDDEN:
                    onPermissionError(ex);          //权限错误,需要实现
                    break;
                case NOT_FOUND:
                case REQUEST_TIMEOUT:
                case GATEWAY_TIMEOUT:
                case INTERNAL_SERVER_ERROR:
                case BAD_GATEWAY:
                case SERVICE_UNAVAILABLE:
                default:
                    ex.setDisplayMessage(networkMsg);  //均视为网络错误
                    onError(ex);
                    break;
            }
        } else if (e instanceof ResultException){    //服务器返回的错误
            ResultException resultException = (ResultException) e;
            ex = new ApiException(resultException, resultException.getErrCode());               
            onResultError(ex);  
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException){
            ex = new ApiException(e, ApiException.PARSE_ERROR);
            ex.setDisplayMessage(parseMsg);            //均视为解析错误
            onError(ex);
        } else {
            ex = new ApiException(e, ApiException.UNKNOWN);
            ex.setDisplayMessage(unknownMsg);          //未知错误
            onError(ex);
        }
    }


    /**
     * 错误回调
     */
    protected abstract void onError(ApiException ex);

    /**
     * 权限错误,需要实现重新登录操作
     */
    protected abstract void onPermissionError(ApiException ex);

    /**
     * 服务器返回的错误
     */
    protected abstract void onResultError(ApiException ex);

    @Override
    public void onCompleted() {

    }

}

自定义ApiException,携带了异常代码和信息,以及根源Throwable,足够调用者需要

public class ApiException extends Exception {

    private final int code;
    private String displayMessage;

    public static final int UNKNOWN = 1000;
    public static final int PARSE_ERROR = 1001;

    public ApiException(Throwable throwable, int code) {
        super(throwable);
        this.code = code;
    }

    public int getCode() {
        return code;
    }
    public String getDisplayMessage() {
        return displayMessage;
    }
    public void setDisplayMessage(String msg) {
        this.displayMessage = msg + "(code:" + code + ")";
    }
}

转自:http://blog.csdn.net/efan006/article/details/50544204


补充:Retrofit+RxJava 优雅的处理服务器返回异常、错误

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Retrofit请求数据对错误以及网络异常的处理 的相关文章

  • 无法连接到 localhost/127.0.0.1 android

    我是 android 开发的新手 并尝试通过改造库调用 android 中的本地 NET Web api 服务 在 IIS 上启动我的 Web api 后 我收到此错误无法连接到 localhost 127 0 0 1 android 当我
  • 如何在 Android 中实现 Webhook?

    例如我想要一个网址www example com status在我的 Android 应用程序中 我将观察该应用程序并将从服务器接收多个 POST 请求 对于每个 POST 请求 我都会触发一个功能 我不明白如何在 URL 上实现 24x7
  • 在 android 中使用 RxJava 和 Retrofit 处理列表

    我需要进行几个 api 调用 顺序 异步 其中一些返回列表 我的api接口如下 GET users settings Observable
  • 改造覆盖端点

    我可以覆盖设置的端点路径吗RestAdapter建造者 假设我有 20 个端点使用相同的基本 URL 但有 1 个端点不使用相同的基本 URL 我想调用 setEndpoint 供所有 20 个使用 但在我需要使用不同基本 URL 的一种情
  • 如何在 RetroFit 中使用 Gson 转换器?

    我正在制作一个用于教育目的的简单 RetroFit 应用程序 并使用 IntelliJ IDEA 作为我的 IDE 我已经正确导入了 Retrofit 库 至少我认为我已经导入了 但我无法获取 Gson Converter 包 我安装了来自
  • 如何通过对象内对象的改造来解析json数据?

    我在网上看到了很多用于改造的 JSON 示例 但无法找到我拥有的 json 结构类型 我无法解决它 我有以下 json 数据 我试图用 java 在我的 android 应用程序中显示它们 main data Date 2020 06 15
  • 使用Retrofit解析本地JSON文件中的文本

    我有一个 JSON 文本文件 res raw 阅读其文本内容后 我想使用 Retrofit 将 JSON 文本解析为 Object 但似乎 Retrofit 只接受服务器中文件的输入 在这种情况下是否可以重用 Retrofit 的 JSON
  • 如何在 RxJava 中延迟地从列表中发出项目?

    我正在使用 Retrofit 从 REST API 获取书签 public interface BookmarkService GET bookmarks Observable
  • Retrofit+OkHttp 发送 GET 请求时可以,但发送 POST 时给出 SocketTimetout

    我从 Retrofit 开始 可以成功执行 GET 请求 但是当我尝试执行 POST 或 PUT 请求时 出现 SocketTimeOut 异常 我根据以下内容将 OkHttp 添加到我的 libs 文件夹中这个问题 https stack
  • 实现 retryWhen 逻辑

    我有一个需要会话 cookie 来处理网络调用的应用程序 我在用着Retrofit RxJava 但是 会话可能会过期 带有 401 未经授权状态的改造错误 在这种情况下我想重新进行身份验证 以获取新的 cookie 并重试之前的调用 我该
  • 在请求正文中发送数组不起作用:使用改造 2.1.0

    将 CustomDishItems 作为数组发送时给出结果 服务器在处理请求时遇到错误 它适用于 CustomDishItems 以下是我使用 PHP Web 服务在服务器上 POST 所需的数据 服务网址 http saavorapi p
  • 从 onResponse Retrofit 返回变量

    我对网络服务器进行 API 调用 并在 onResponse 方法中获取 ID 现在我想保存这个ID并在doLogin方法的返回中返回这个ID 如何在 return 语句中获取该变量 ID 这是我的代码 public class Login
  • 如何在 Android 上使用 GraphQL 和 Retrofit?

    我是 GraphQL 的新手 但我已经使用 Retrofit 一段时间了 它易于使用且快速 GraphQL 在传递数据的方式方面与 REST API 有很大不同 关于在 Android 上使用 GraphQL 的教程确实不多 我只能找到这个
  • 如何在Android中检查Retrofit API调用是否成功

    这是我的代码 通过这种方法 我将一些数据发送到我的 API 服务器如果数据接收成功success里面的变量将为 trueonResponse method private boolean success false public boole
  • 如何在 OnResponse 函数之外使用 Retrofit 响应?

    我想获取改造响应列表并在 OnResponse 函数之外使用它 但是当我尝试这样做时 我总是得到一个空对象 这是我的源代码 ApiInterface apiService ApiClient getClient create ApiInte
  • 如何使用 Retrofit 传递数组参数?

    我想要post数据如下 user id 14545646 list 4545645 4545645 4545645 4545645 我用了以下Retrofit method interface DeleteOrder FormUrlEnco
  • Retrofit 2.0 如何解析嵌套的 JSON 对象?

    我们的团队决定使用改造2 0 http square github io retrofit 我正在对这个库进行一些初步研究 如标题所述 我想通过 Android 应用程序中的 Retrofit 2 0 解析一些嵌套的 JSON 对象 例如
  • RETROFIT 如何解析此响应

    我正在尝试解析这个 json 响应雅虎YQL http chartapi finance yahoo com instrument 1 0 goog chartdata type quote range 1d json使用 Retrofit
  • 使用 Retrofit 的 Google 地图方向 API

    我想绘制两个位置之间的路线 我使用retrofit库来调用API 我没有得到任何回应 我需要 ArrayList 中的折线 我怎么做到这一点 还需要帮助来创建 GsonAdapter 谢谢 在活动中 String base url http
  • 使用 Retrofit 获取原始 HTTP 响应

    我想从我的 API REST 获取原始 http 响应 我尝试过这个界面 POST login FormUrlEncoded Call

随机推荐