美文网首页app开发Android开发
json数据解析异常而导致网络请求失败的解决办法(其一)

json数据解析异常而导致网络请求失败的解决办法(其一)

作者: Abtion | 来源:发表于2017-08-21 18:52 被阅读917次

    参考文章

    问题概述

    笔者在开发过程中临时遇到一个本来仅有web端的项目临时增加Android端,导致后端在出接口时并未考虑Android端的json数据的解析,导致接口是这样的。。。。

    • 正确请求
    {
        "code": 0,
        "data": {
            "user": {
                "id": 145,
                "name": "abtion",
                "school_id": 1,
                "sex": "男",
                "add_on": null,
                "status": 1,
                "role": "student",
                "created_at": "2017-08-05 18:26:31",
                "updated_at": "2017-08-19 12:41:50"
            }
        }
    }
    
    • 错误请求
    {
        "code": 20002,
        "data": "Password Wrong"
    }
    

    这也就是说在请求正确时服务端返回的数据中data是在java中的一个对象,而错误时却变成了String,这就导致了错误的请求在解析json时抛出异常导致请求失败,而且抛出的异常是无法拿到错误码和错误信息的。

    问题分析

    我们该如何解决这个问题呢,经过思考,方法有三:

    • 呼叫可爱的后端老哥改接口,将错误信息改由message字段输出
    • okhttp添加拦截器,在retrofit解析json前解析json数据并存储。
    • 自定义Gson响应体变换器和响应变换工厂,在请求错误时抛出异常并保存错误码和错误信息。

    由于该项目已经上线,再改接口无异于痴人说梦,因加拦截器的效率也不及第三种方法日后再分享,本次采用自定义Gson响应体变换器和响应变换工厂的方法来解决。

    具体解决办法

    1、切入点

    首先请看一张图片

    我们通常情况下跟图中一样采用的是Gosn工厂变换器,而本次抛出异常的地方就是这个变换器,自定义工厂变换器就可以完美解决我们的问题。

    2、自定义Gson响应体变换器

    class GsonResponseBodyConverter<T> implements Converter<ResponseBody,T> {
        private final Gson gson;
        private final Type type;
    
        public GsonResponseBodyConverter(Gson gson, Type type) {
            this.gson = gson;
            this.type = type;
        }
    
    
        @Override
        public T convert(ResponseBody value) throws IOException {
            //将返回的json数据储存在String类型的response中
            String response = value.string();
            //将外层的数据解析到APIResponse类型的httpResult中
            APIResponse httpResult = gson.fromJson(response,APIResponse.class);
            //服务端设定0为正确的请求,故在此为判断标准
            if (httpResult.getCode()==0){
                //直接解析,正确请求不会导致json解析异常
                return gson.fromJson(response,type);
            }else {
                //定义错误响应体,并通过抛出自定义异常传递错误码及错误信息
                ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class);
                throw new ResultException(errorResponse.getCode(),errorResponse.getData());
            }
        }
    }
    

    附上APIResponse类,ErrorResponse类和ResultException类

    public class APIResponse<T> extends BaseModel {
        private int code = -2;
        private T data;
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    
    
    public class ErrorResponse {
        private int code;
        private String data;
    
        public ErrorResponse(int code, String data) {
            this.code = code;
            this.data = data;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getData() {
            return data;
        }
    
        public void setData(String data) {
            this.data = data;
        }
    }
    
    
    
    public class ResultException extends IOException {
        private int code;
        private String msg;
    
    
    
        public ResultException(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
    

    3、自定义响应变换工厂

    class ResponseConverterFactory extends Converter.Factory {
    
        public static ResponseConverterFactory create() {
            return create(new Gson());
        }
    
    
        public static ResponseConverterFactory create(Gson gson) {
            return new ResponseConverterFactory(gson);
        }
    
        private final Gson gson;
    
        private ResponseConverterFactory(Gson gson) {
            if (gson == null) throw new NullPointerException("gson == null");
            this.gson = gson;
        }
    
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, java.lang.annotation.Annotation[] annotations, Retrofit retrofit) {
            return new GsonResponseBodyConverter<>(gson,type);
        }
    
        @Override
        public Converter<?, RequestBody> requestBodyConverter(Type type, java.lang.annotation.Annotation[] parameterAnnotations, java.lang.annotation.Annotation[] methodAnnotations, Retrofit retrofit) {
            TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
            return new GsonRequestBodyConverter<>(gson, adapter);
        }
    }
    

    4、调用自定义的响应变换工厂

    在构造Retrofit时在addConverterFactory()方法中传入ResponseConverterFactory.create()就可以了。

    /**
         * 构造Retrofit
         *
         * @return retrofit
         */
        private static Retrofit getRetrofit() {
            if (retrofit == null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(Config.APP_SERVER_BASE_URL)
                        .addConverterFactory(ResponseConverterFactory.create())
                        .client(getClient())
                        .build();
            }
            return retrofit;
        }
        
    

    5、在网络请求的onFailure中接收异常信息并进行处理

    @Override
                    public void onFailure(Call<APIResponse<LoginResponse>> call, Throwable t) {
                        if (t instanceof ResultException) {
                            ToastUtil.showToast(((ResultException) t).getMsg(), ((ResultException) t).getCode());
                        } else {
                            ToastUtil.showToast("网络请求失败,请稍后再试");
                        }
                    }
                    
    

    到这里就完成了,别忘了Gson的请求体变换器是default限定的。改改限定符就好了。

    相关文章

      网友评论

        本文标题:json数据解析异常而导致网络请求失败的解决办法(其一)

        本文链接:https://www.haomeiwen.com/subject/kgshdxtx.html