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

您所在的位置:网站首页 解析json数据错误 json数据解析异常而导致网络请求失败的解决办法(其一)

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

2023-07-07 23:45| 来源: 网络整理| 查看: 265

参考文章

问题概述

笔者在开发过程中临时遇到一个本来仅有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 implements Converter { 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 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 responseBodyConverter(Type type, java.lang.annotation.Annotation[] annotations, Retrofit retrofit) { return new GsonResponseBodyConverter(gson,type); } @Override public Converter 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 call, Throwable t) { if (t instanceof ResultException) { ToastUtil.showToast(((ResultException) t).getMsg(), ((ResultException) t).getCode()); } else { ToastUtil.showToast("网络请求失败,请稍后再试"); } }

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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3