package com.duqing.missions.retrofit.Interceptor; import android.util.Log; import com.duqing.missions.retrofit.NetWorkCost; import com.duqing.missions.retrofit.NetWorkListenear; import com.duqing.missions.retrofit.utils.HttpPrintUtils; import com.duqing.missions.util.GsonUtils; import org.json.JSONObject; import java.io.EOFException; import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import okhttp3.FormBody; import okhttp3.Headers; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; import okhttp3.internal.http.HttpHeaders; import okio.Buffer; import okio.BufferedSource; /** * My father is Object, ites purpose of log打印 * * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-10-21. */ public class HttpLoggingInterceptor extends EncryptInterceptor { final String TAG = "HttpLogging"; public HttpLoggingInterceptor() { } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); int hashCode = request.hashCode(); ArrayList logArrays = getRequestLog(request); int position = logArrays.size() +2; Response response; try { //request = encryptRequest(request);//加密 response = chain.proceed(request); logArrays.addAll(getResponseLog(response)); Log.d(TAG,"hashcode:"+hashCode); NetWorkCost netWorkCost = NetWorkListenear.workCostMap.get(hashCode); if(netWorkCost != null) { String cost = String.format("dns:%s,secure:%s,connect:%s,requestH:%s,requestB:%s,responseH:%s,responseB:%s", convertTimes(netWorkCost.dns), convertTimes(netWorkCost.secure), convertTimes(netWorkCost.connect), convertTimes(netWorkCost.requestHeader), convertTimes(netWorkCost.requestBody), convertTimes(netWorkCost.resposeHeader), convertTimes(netWorkCost.resposeBody)); logArrays.add(position, "<-- costtimes : " + convertTimes(netWorkCost.total) + " (" + cost + ')'); } NetWorkListenear.workCostMap.remove(hashCode); new Thread(){ @Override public void run() { HttpPrintUtils.getInstance().printLog(logArrays, true);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应 } }.start(); } catch (Exception e) { logArrays.add("<-- response url:" + URLDecoder.decode(request.url().toString(), "UTF-8")); NetWorkCost netWorkCost = NetWorkListenear.workCostMap.get(hashCode); String cost = String.format("dns:%s,secure:%s,connect:%s,requestH:%s,requestB:%s,responseH:%s,responseB:%s", convertTimes(netWorkCost.dns) ,convertTimes(netWorkCost.secure) , convertTimes(netWorkCost.connect),convertTimes(netWorkCost.requestHeader),convertTimes(netWorkCost.requestBody) ,convertTimes(netWorkCost.resposeHeader),convertTimes(netWorkCost.resposeBody) ); logArrays.add("<-- costtimes : "+convertTimes(netWorkCost.total)+" (" +cost + ')'); logArrays.add("<-- response failed " + e.getLocalizedMessage()); logArrays.add("<-- " + e.toString()); new Thread(){ @Override public void run() { HttpPrintUtils.getInstance().printLog(logArrays, false);//线程安全方法,需在新线程执行,避免阻塞当前线程,导致程序无响应 } }.start(); throw e;//抛出异常,用于请求接收信息 } return response; } private ArrayList getRequestLog(Request request) throws IOException { RequestBody requestBody = request.body(); ArrayList logArrays = new ArrayList<>(); String requestStartMessage = "--> " + request.method() + ' ' + URLDecoder.decode(request.url().toString() ,"UTF-8")+ ' ' ; if ( requestBody != null) { requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; } logArrays.add(requestStartMessage); Headers headers = request.headers(); logArrays.add("---------->REQUEST HEADER<----------"); for (int i = 0, count = headers.size(); i < count; i++) { logArrays.add(headers.name(i) + ": " + headers.value(i)); } if (requestBody == null) { logArrays.add("--> END " + request.method()); } else if (bodyEncoded(request.headers())) { logArrays.add("--> END " + request.method() + " (encoded body omitted)"); } else { Charset charset = UTF8; MediaType contentType = requestBody.contentType(); if (contentType != null) { charset = contentType.charset(UTF8); } HashMap param = new HashMap(); if(requestBody instanceof MultipartBody){ logArrays.add("---------->REQUEST BODY[MultipartBody]<----------"); MultipartBody body = (MultipartBody) requestBody; for(MultipartBody.Part part:body.parts()){ Buffer buffer1 = new Buffer(); part.body().writeTo(buffer1); String str=buffer1.readString(charset).replaceAll("%(?![0-9a-fA-F]{2})","%25"); param.put(part.headers().get(part.headers().name(0)),URLDecoder.decode(str, "UTF-8")); } logArrays.add(GsonUtils.retractJson(new JSONObject(param).toString())); }else if(requestBody instanceof FormBody){ logArrays.add("---------->REQUEST BODY[FormBody]<----------"); FormBody body = (FormBody) requestBody; for(int i = 0 ; i < body.size() ; i ++ ){ param.put(body.name(i),body.value(i)); } logArrays.add(GsonUtils.retractJson(new JSONObject(param).toString())); }else{ Buffer buffer = new Buffer(); requestBody.writeTo(buffer); logArrays.add("---------->REQUEST BODY<----------"); String str = buffer.readString(charset); try{ logArrays.add(GsonUtils.retractJson(URLDecoder.decode(str, "UTF-8"))); }catch (Exception e){ logArrays.add(str); } } logArrays.add("--> END " + request.method() + " " + contentType + " ( " + requestBody.contentLength() + "-byte body )"); } return logArrays; } private ArrayList getResponseLog(Response response) throws IOException { ArrayList logArrays = new ArrayList<>(); ResponseBody responseBody = response.body(); long contentLength = responseBody.contentLength(); String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; logArrays.add("<-- response code:" + response.code() + " message:" + response.message()+" contentlength:"+bodySize ); logArrays.add("<-- response url:"+URLDecoder.decode(response.request().url().toString(),"UTF-8") ); if ( !HttpHeaders.hasBody(response)) { logArrays.add("<-- END HTTP"); } else if (bodyEncoded(response.headers())) { logArrays.add("<-- END HTTP (encoded body omitted)"); } else { BufferedSource source = responseBody.source(); source.request(Long.MAX_VALUE); // Buffer the entire body. Buffer buffer = source.buffer(); Charset charset = UTF8; MediaType contentType = responseBody.contentType(); if (contentType != null) { charset = contentType.charset(UTF8); } if (isPlaintext(buffer)) { logArrays.add("---------->RESPONSE BODY<----------"); if (contentLength != 0) { logArrays.add(retractJson(buffer.clone().readString(charset))); } logArrays.add("<-- END HTTP (" + buffer.size() + "-byte body)"); } } return logArrays; } /** * 字符串缩进 * @param json * @return */ private String retractJson(String json){ int level = 0 ; StringBuffer jsonForMatStr = new StringBuffer(); for(int index=0;index 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) { jsonForMatStr.append(getLevelStr(level)); // System.out.println("123"+jsonForMatStr); } //遇到"{"和"["要增加空格和换行,遇到"}"和"]"要减少空格,以对应,遇到","要换行 switch (c) { case '{': case '[': jsonForMatStr.append(c + "\n"); level++; break; case ',': jsonForMatStr.append(c + "\n"); break; case '}': case ']': jsonForMatStr.append("\n"); level--; jsonForMatStr.append(getLevelStr(level)); jsonForMatStr.append(c); break; default: jsonForMatStr.append(c); break; } } return jsonForMatStr.toString(); } private String getLevelStr(int level) { StringBuffer levelStr = new StringBuffer(); for (int levelI = 0; levelI < level; levelI++) { levelStr.append("\t");//\t或空格 } return levelStr.toString(); } /** * Returns true if the body in question probably contains human readable text. Uses a small sample * of code points to detect unicode control characters commonly used in binary file signatures. */ static boolean isPlaintext(Buffer buffer) { 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; // Truncated UTF-8 sequence. } } private boolean bodyEncoded(Headers headers) { String contentEncoding = headers.get("Content-Encoding"); return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); } private String convertTimes(long ms){ String m = null,s=null; final int utilS = 1000; final int utilM = utilS*60; if(ms/utilM>0){ m = ms/utilM+"m"; } if(ms%utilM/utilS>0){ s = ms%utilM/utilS+"s"; } return (m!=null?m:"")+(s!=null?s:"")+ms%utilS+"ms"; } }