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

参考: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;
    }
}
原文地址:https://www.cnblogs.com/duguxiaobiao/p/12092231.html