Okhttp拦截器统一异常处理并多次读取response.body().string()

您所在的位置:网站首页 每次都是网络请求运行数据异常 Okhttp拦截器统一异常处理并多次读取response.body().string()

Okhttp拦截器统一异常处理并多次读取response.body().string()

2024-07-13 11:27:12| 来源: 网络整理| 查看: 265

Okhttp中的response.body()只能访问一次,相信大部分人都已经踩过这个坑。在那个retrofit还没火起来的年代,大家都只是用okhttp然后自己封装,当时都是把response.body().string()用一个String保存起来随便传了。 但如今项目用的是retrofit + okhttp的网络层,在项目中打算加一个统一的异常处理,想了很久,感觉最简单的方式还是通过拦截器Interceptor的方式感觉最方便。想好了实现方式,开始好好屡一下实现的逻辑。 1、自定义拦截器,实现intercept方法 2、在intercept方法内读取json数据判断是否特定的异常统一处理 3、添加拦截器 逻辑比较简单,但是中途发现自定义处理后的后续处理不太正常

/** * @Description 网络拦截器。 **/ private Interceptor getIns() { Interceptor interceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); String res = response.body().string() Constant.LogE(TAG, " response.url():"+ url); Constant.LogE(TAG, " response.body():"+ res); BaseBean baseBean = new Gson().fromJson( res,BaseBean.class); if(baseBean.getState() == -401) { //异常处理 } return response; } }; return interceptor; }

经过一番调试,发现问题出在String res = response.body().string()上面。但这里又需要读取string的json数据。 看源码

/** * Returns the response as a string decoded with the charset of the Content-Type header. If that * header is either absent or lacks a charset, this will attempt to decode the response body as * UTF-8. */ public final String string() throws IOException { return new String(bytes(), charset().name()); }

继续磕

public final byte[] bytes() throws IOException { long contentLength = contentLength(); if (contentLength > Integer.MAX_VALUE) { throw new IOException("Cannot buffer entire body for content length: " + contentLength); } BufferedSource source = source(); byte[] bytes; try { bytes = source.readByteArray(); } finally { Util.closeQuietly(source); } if (contentLength != -1 && contentLength != bytes.length) { throw new IOException("Content-Length and stream length disagree"); } return bytes; }

问题来了,桥黑板!!!划重点了!!!! Util.closeQuietly(source);

看看源码

/** * Closes {@code closeable}, ignoring any checked exceptions. Does nothing if {@code closeable} is * null. */ public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (RuntimeException rethrown) { throw rethrown; } catch (Exception ignored) { } } }

谷歌翻译下注释 关闭{@code closeable},忽略任何已检查的异常。如果{@code closeable}是空值。

问题找到了,细看源码会发现ResponseBody类以及其他大部分类都implements Closeable。问题找到了,如何解决呢?

okhttp有个log打印类HttpLoggingInterceptor,为什么他就可以读出来而不影响传递呢?继续磕源码

public final class HttpLoggingInterceptor implements Interceptor { private static final Charset UTF8 = Charset.forName("UTF-8"); @Override public Response intercept(Chain chain) throws IOException { Level level = this.level; Request request = chain.request(); //如果Log Level 级别为NONOE,则不打印,直接返回 if (level == Level.NONE) { return chain.proceed(request); } //是否打印body boolean logBody = level == Level.BODY; //是否打印header boolean logHeaders = logBody || level == Level.HEADERS; //获得请求body RequestBody requestBody = request.body(); //请求body是否为空 boolean hasRequestBody = requestBody != null; //获得Connection,内部有route、socket、handshake、protocol方法 Connection connection = chain.connection(); //如果Connection为null,返回HTTP_1_1,否则返回connection.protocol() Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; //比如: --> POST http://121.40.227.8:8088/api http/1.1 String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol; if (!logHeaders && hasRequestBody) { requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; } logger.log(requestStartMessage); //打印 Request if (logHeaders) { if (hasRequestBody) { // Request body headers are only present when installed as a network interceptor. Force // them to be included (when available) so there values are known. if (requestBody.contentType() != null) { logger.log("Content-Type: " + requestBody.contentType()); } if (requestBody.contentLength() != -1) { logger.log("Content-Length: " + requestBody.contentLength()); } } Headers headers = request.headers(); for (int i = 0, count = headers.size(); i < count; i++) { String name = headers.name(i); // Skip headers from the request body as they are explicitly logged above. if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { logger.log(name + ": " + headers.value(i)); } } if (!logBody || !hasRequestBody) { logger.log("--> END " + request.method()); } else if (bodyEncoded(request.headers())) { logger.log("--> END " + request.method() + " (encoded body omitted)"); } else { Buffer buffer = new Buffer(); requestBody.writeTo(buffer); //编码设为UTF-8 Charset charset = UTF8; MediaType contentType = requestBody.contentType(); if (contentType != null) { charset = contentType.charset(UTF8); } logger.log(""); if (isPlaintext(buffer)) { logger.log(buffer.readString(charset)); logger.log("--> END " + request.method() + " (" + requestBody.contentLength() + "-byte body)"); } else { logger.log("--> END " + request.method() + " (binary " + requestBody.contentLength() + "-byte body omitted)"); } } } //打印 Response long startNs = System.nanoTime(); Response response; try { response = chain.proceed(request); } catch (Exception e) { logger.log("


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭