okhttp通过反射在服务器回400错误的情况下拿到返回的数据

793 阅读2分钟

一般来说,服务器回400错误是由于客户端发的请求格式有问题. 

400 Bad Request 是由于明显的客户端错误(例如,格式错误的请求语法,太大的大小,无效的请求消息或欺骗性路由请求),服务器不能或不会处理该请求。

但是,遇到了一家比较奇葩的公司,请求逻辑正常该回200的情况下回了400.业务逻辑的错误跟客户端请求逻辑错误混在一起..... 

{"code":752, "success":false, "data":{},"msg":"用户无法找到", ...}

服务器能正常返回数据,说明出问题的地方是业务逻辑,但是服务器回400,客户端就只能走onError(Throwable e)回调,拿不到这个msg,用户就不知道是什么问题,就会跑来反馈说这是什么垃圾app,用都用不了...

忍住脏话,考虑兼容

既然okhttp的log拦截器HttpLoggingInterceptor能拿到这串数据,说明至少有两种方法可以获取到.一是重写该拦截器;二是用反射...

懒得重写一个,所以用第二种方法

看一下代码的日志打印,可以发现上面的log是在HttpLoggingInterceptor.intercept(Chain chain)方法中实现的,根据日志分析一下可以知道就是buffer这串字符串取出来的数据.

if (responseBody.contentLength() != 0) {
  logger.log("");
  logger.log(buffer.clone().readString(charset));
}

logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");

看一下代码前后的生成过程,发现该数据在方法里是局部变量里.

Java 反射不支持访问局部变量。因为局部变量是存储在方法栈上的,它们在方法结束后就消失了,无法被反射访问。

这个局部变量拿不到,反射调用intercept(Chain chain)方法的话需要传参,不太行

所以之恩呢把这个HttpLoggingInterceptor类拿出来,放到项目里. 在类里加上全局变量send,并把值赋上

public static String send = "";   //定义全局变量if (responseBody.contentLength() != 0) {
  logger.log("");
  logger.log(buffer.clone().readString(charset));
  send = buffer.clone().readString(charset);  //赋值
}

然后在网络回调的onError中反射该值就可以拿到了

@Override
public void onError(Throwable e) {
    String msg = "失败状态";
    try{
        //拿到HttpLoggingInterceptor类的实例
        Object object = HttpLoggingInterceptor.class.newInstance();
        Field send = object.getClass().getField("send");    //反射获取属性
        JSONObject json = JSONObject.parseObject((String) send.get(object));
        System.out.println("json: " + json);        msg = json.getString("msg");
        System.out.println(msg);
    }catch(Exception q){
        System.out.println(getStackTraceString(q));    }
}