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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM