参考:https://blog.csdn.net/a624806998/article/details/73863606

引言: 写这篇文章,因为在自己编写实现Http日志拦截器的时候,在拦截器中使用 response.body().string() 获取了返回的数据,但是在经过拦截器后,针对输出处理的时候,会再次调用 response.body().string(),这里就会导致流已关闭的异常。

参考上面的链接,修改了在拦截器中的response中的数据获取。保证了下一步的输出流的处理获取操作。

下面的就是能使用的的Http拦截器代码

package com.ztkj.common.log.interceptors;

import com.alibaba.fastjson.JSON;
import com.ztkj.common.log.aspect.bean.HttpHandlerBean;
import com.ztkj.common.log.aspect.bean.LinkTrackingBean;
import com.ztkj.common.log.aspect.threadlocals.LinkTrackingThreadLocal;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.EOFException;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.List;
import java.util.Map;
import java.util.UUID; /**
* okhttp 拦截器定义: 统计请求信息以及耗时
*
* @author hzb-ztkj
*/
public class HttpLogInterceptor implements Interceptor { private static final Logger logger = LoggerFactory.getLogger(HttpLogInterceptor.class); private static final Charset UTF8 = Charset.forName("UTF-8"); /**
* 拦截过程中 收集 http请求输入、输出等信息,日志输出打印
*
* @param chain
* @return
* @throws IOException
*/
@Override
public Response intercept(Chain chain) throws IOException { //获取当前请求
Request request = chain.request(); //根据请求类型分析
HttpHandlerBean httpHandlerBean = new HttpHandlerBean(); //从http request中获取请求信息
httpHandlerBean.setUrl(request.url().toString()); //设置请求头信息
Headers headers = request.headers();
Map<String, List<String>> stringListMap = headers.toMultimap();
httpHandlerBean.setParamHeaderStr(JSON.toJSONString(stringListMap)); //设置请求body信息
RequestBody requestBody = request.body();
if (requestBody != null) {
httpHandlerBean.setParamStr(getParam(requestBody));
} //设置请求方式
httpHandlerBean.setRequestMode(request.method()); Response response = null;
try {
response = chain.proceed(request); //设置状态码
httpHandlerBean.setCode(response.code() + ""); //设置响应头信息
Map<String, List<String>> responseHeaderMap = response.headers().toMultimap();
httpHandlerBean.setResultHeaderStr(JSON.toJSONString(responseHeaderMap)); //设置响应信息
ResponseBody responseBody = response.body();
if (responseBody != null) {
//httpHandlerBean.setResultStr(JSON.toJSONString(responseBody.string()));
httpHandlerBean.setResultStr(getResponseBody(responseBody));
} //设置用时信息
httpHandlerBean.setSendTime(response.sentRequestAtMillis());
httpHandlerBean.setReceiveTime(response.receivedResponseAtMillis()); //设置唯一性id
LinkTrackingBean linkTrackingBean = LinkTrackingThreadLocal.get();
if (linkTrackingBean == null) {
httpHandlerBean.setRequestId(UUID.randomUUID().toString());
} else {
httpHandlerBean.setRequestId(linkTrackingBean.getRequestId());
httpHandlerBean.setUserId(linkTrackingBean.getUserId());
httpHandlerBean.setProductId(linkTrackingBean.getProductId());
} //响应消息
httpHandlerBean.setMessage(response.message()); } catch (Exception e) {
logger.error("处理请求异常,异常原因:{}", ExceptionUtils.getStackTrace(e));
httpHandlerBean.setMessage(ExceptionUtils.getStackTrace(e));
} //输出,打印日志
logger.info(httpHandlerBean.httpLogPrint()); return response;
} private String getResponseBody(ResponseBody responseBody) throws Exception {
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE);
Buffer buffer = source.buffer(); Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
try {
charset = contentType.charset(UTF8);
} catch (UnsupportedCharsetException e) {
logger.error("将http数据写入流异常,异常原因:{}", ExceptionUtils.getStackTrace(e));
}
} if (!isPlaintext(buffer)) {
return null;
} if (responseBody.contentLength() != 0) {
String result = buffer.clone().readString(charset);
return result;
}
return null;
} private boolean isPlaintext(Buffer buffer) throws EOFException {
try {
Buffer prefix = new Buffer();
long byteCount = buffer.size() < 64 ? buffer.size() : 64;
buffer.copyTo(prefix, 0, byteCount);
for (int i = 0; i < 16; i++) {
if (prefix.exhausted()) {
break;
}
int codePoint = prefix.readUtf8CodePoint();
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
return false;
}
}
return true;
} catch (EOFException e) {
return false;
}
} /**
* 读取参数
*
* @param requestBody
* @return
*/
private String getParam(RequestBody requestBody) {
Buffer buffer = new Buffer();
String logparm;
try {
requestBody.writeTo(buffer);
logparm = buffer.readUtf8();
logparm = URLDecoder.decode(logparm, "utf-8");
} catch (IOException e) {
e.printStackTrace();
return "";
}
return logparm;
}
}

Okhttp拦截器统一异常处理并多次读取response.body().string()的更多相关文章

  1. 从网络请求过程看OkHttp拦截器

    前言 之前我们结合设计模式简单说了下OkHttp的大体流程,今天就继续说说它的核心部分--拦截器. 因为拦截器组成的链其实是完成了网络通信的整个流程,所以我们今天就从这个角度说说各拦截器的功能. 首先 ...

  2. SpringMVC——自定义拦截器、异常处理以及父子容器配置

    自定义拦截器: 一.若想实现自定义拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口. 二.HandlerIntercepto ...

  3. JavaEE开发之SpringMVC中的自定义拦截器及异常处理

    上篇博客我们聊了<JavaEE开发之SpringMVC中的路由配置及参数传递详解>,本篇博客我们就聊一下自定义拦截器的实现.以及使用ModelAndView对象将Controller的值加 ...

  4. SpringMVC(四)-- 文件下载、自定义拦截器、异常处理

    1.文件下载 用ResponseEntity<byte[]> 返回值完成文件下载 具体参见本博客之前的<文件上传下载> @RequestMapping(value=" ...

  5. SpringBoot系统列 4 - 常用注解、拦截器、异常处理

    在前面代码基础上进行改造: 1.SpringBoot常用注解 @SpringBootApplication :指定SpringBoot项目启动的入口,是一个复合注解,由@Configuration.@ ...

  6. SpringMVC入门一:基础知识(依赖、注解、文件上传/下载、拦截器、异常处理等)

    为了使Spring可插入MVC架构,SpringFrameWork在Spring基础上开发SpringMVC框架,从而使用Spring进行WEB开发时可以选择使用Spring的SpringMVC框架作 ...

  7. SpringMVC拦截器与异常处理

    点击查看上一章 在我们SpringMVC中也可以使用拦截器对用户的请求进行拦截,用户可以自定义拦截器来实现特定的功能.自定义拦截器必须要实现HandlerInterceptor接口 package c ...

  8. OkHttp拦截器的实现原理

    今天项目中遇到需要将从push接收到的数据按照协议parse成应用层需要的结构化数据类型问题:因为push消息类型繁多,等待解析出的结构化数据类型也多样,有的还需要经过几步的parse过程:而且因为项 ...

  9. axios封装,使用拦截器统一处理接口

    1.项目路径下,引入axios.qs依赖 npm install axios npm install qs 2.在项目的src路径下新建一个commJs文件夹,在commJs文件夹里新建aps.js和 ...

随机推荐

  1. golang init方法和main方法初始化顺序

    init()和main()方法是golang默认的两个方法,不需要我们调用,程序执行会自动寻找项目中的这俩方法.现在我们就讲一种通用的情况:main 包下 导入了 init2 包而在init2 包下又 ...

  2. jenkins 配置 gitlab webhook 实现自动发布

    测试环境需要git提交代码后,Jenkins自动部署,需要gitlab配置project webhook. 1,Jenkins版本2.89  gitlab 8.11 2,Jenkins需要安装插件:G ...

  3. Unity 动画属性

    在动画的使用上使用不当的设置往往会造成不可预料的结果. 首先,如果动画自身可以驱动物体移动,那么在Animator组件上必须选择apply root motion,物体的动画位移才能生效,否则动画只能 ...

  4. 引用dll出现了黄色感叹号

    今天引用一个dll的时候出现了一个小感叹号,重新生成也无济于事,如下图 原因是,被引用的项目使用的是.NET2.0版本,而当前项目使用的是.NET3.5版本,所以出现了错误 解决办法把当前项目和引用项 ...

  5. MVC学习途径

    博客园专题:http://kb.cnblogs.com/zt/mvc/ MVC源码:http://www.codeplex.com/site/search?projectSearchText=mvc ...

  6. python 并发编程 多线程 多线程实现并发的套接字通信

    进程内会生成一个主线程,让主线程执行server函数,server函数核心是accept(),让主线程干accept的工作, 建立连接,每建立一个连接应该执行通信函数 每建立一个连接就是生成一个子线程 ...

  7. CSRF-DVWA_1.9-笔记

     CSRF : Cross-site request forgery  跨站请求伪造   所用到的工具: Firefox浏览器及其插件     HackBar(快速构造URL)     和     T ...

  8. Anaconda配置环境变量+创建虚拟环境+pycharm使用虚拟环境

    Anaconda配置环境变量+创建虚拟环境 配置环境变量 没有添加系统变量,所有系统根本识别不了conda命令,找不到位置,所以添加以下系统变量: 添加对应Anaconda环境变量:(以自己的安装路径 ...

  9. List<HashMap<String,String>> list, 根据hashmap中的某个键的值排序

    来源https://blog.51cto.com/zhaodan/1725249 //可以使用Collections.sort(List list, Comparator c)来实现 这里举例hash ...

  10. jQuery-点击按钮页面滚动到顶部,底部,指定位置

    $('.scroll_top').click(function(){$('html,body').animate({scrollTop: '0px'}, 800);}); //页面滚动至顶部 $('. ...