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

异常处理

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

时间: 2024-12-05 20:59:40

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

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

开始本博客之前,请先阅读: Retrofit请求数据对错误以及网络异常的处理 异常&错误 实际开发经常有这种情况,比如登录请求,接口返回的 信息包括请求返回的状态:失败还是成功,错误码,User对象等等.如果网络等原因引起的登录失败可以归结为异常,如果是用户信息输入错误导致的登录失败算是错误. 假如服务器返回的是统一数据格式: /** * 标准数据格式 * @param <T> */ public class Response<T> { public int state;

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

开始本博客之前,请先阅读: Retrofit请求数据对错误以及网络异常的处理 异常&错误 实际开发经常有这种情况,比如登录请求,接口返回的 信息包括请求返回的状态:失败还是成功,错误码,User对象等等.如果网络等原因引起的登录失败可以归结为异常,如果是用户信息输入错误导致的登录失败算是错误. 假如服务器返回的是统一数据格式: /** * 标准数据格式 * @param <T> */ public class Response<T> { public int state;

转-封装网络请求库,统一处理通用异常 (基于volley网络请求库)

http://blog.csdn.net/kroclin/article/details/40540761 一.前言 volley的发布让网络请求也变得十分便利,但是我们通常懒得很想用一两句代码实现一个网络请求,其实你再经过封装就可以做到的.还有就是实际开发当中,我们会常常遇到很多异常情况,如网络异常.超时异常等等,那么我们如果有10个activity需要请求数据,那么在10个activity当中都去处理这些异常就变得十分麻烦,通过合理的设计其实我们能够在一个地方对异常情况进行统一处理,只有正确

Android Retrofit 请求字符串(非JSON数据)

在使用Retrofit来作为网络请求库之后,笔者查阅了网上的有关教程,无外乎都是请求json数据,使用addConverterFactory(GsonConverterFactory.create())来作为转化器,如果业务需求是请求 字符串,而不是json数据格式呢,继续使用这个转换器就会产生错误. 好,来到正题,如何使用Retrofit请求一段字符串: 来到官方文档查阅:http://square.github.io/retrofit/ 有如下描述: 其实官方已经提供了一个字符串的转换器,那

Swift 网络请求数据与解析

一: Swift 网络数据请求与处理最常用第三方 又有时间出来装天才了,还是在学swift,从中又发现一些问题,这两天上网找博客看问题弄的真的心都累.博客一篇写出来,好多就直接照抄,就没有实质性的把问题解决了,只是在发表的博客数量上 + 1 !!真心没意思.. 看看在Swift中是在怎样请求数据,解析数据加载图片这些的,也使我们最基本最常见的用法了,先说说这几个三方库: 第一个: Alamofire  (它的原作者就是AFNetworking的原作者,这个就不多说了,你要知道AFNetworki

网络请求数据 get请求方式 &nbsp; post请求 协议异步连接服务器 block异步连接服务器

网络请求三部 创建一个请求(添加接口,对接口进行解码,) 设定请求方式(将接口转为NSURL,设置请求[请求地址, 缓存策略, 超时时间],设置请求方式) 连接服务器([同步连接,异步连接]代理连接,block连接) #import "MainViewController.h" @interface MainViewController () @property (retain, nonatomic) IBOutlet UIImageView *ImageWiew; //get请求方法

IOS开发之网络编程(请求数据和断点续传)

IOS开发中网络编程应用场景:JSON数据获取,网络数据的下载. 一:请求JSON数据一般用异步请求的方式,如果用同步请求,则会造成IOS界面的执行过程阻塞,即界面部分在请求数据的过程中必须等待数据加载完毕. JSON数据的获取步骤: 1.设置网络地址的字符串:NSString *URLString = @"http://www.baidu.com"; 2.创建URL:NSURL *URL = [NSURL URLWithString:URLString]; 3.创建请求:NSURLR

AFNetworking请求数据总是返回错误的修改

最近我看到很多AFNet的教程,我就在想怎么那么多人不明白怎么用AFNet.很多人回答的问题都是一样的怎么还有人不会用.我估计很多人都遇到了这个错误 我运行了 这段代码 AFHTTPRequestOperationManager  * manager  =  [ AFHTTPRequestOperationManager  manager ]; [manager GET:@"http://211.154.151.249:8866/ogPortal/getCarType.do"param

用JQuery Ajax 与一般处理程序 请求数据无刷新,以及如何调试错误

通过 ajax() 与 一般处理程序,请求数据库数据,实现界面无刷新. Jquery ajax 请求参数详细说明 http://www.w3school.com.cn/jquery/ajax_ajax.asp 代码: 1 <!DOCTYPE html> 2 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head runat="server"> 5 <meta http-eq