package com.yutou.okhttp; import com.yutou.qqbot.utlis.Log; import lombok.val; import okhttp3.*; import okhttp3.internal.http.HttpHeaders; import okio.Buffer; import okio.BufferedSource; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; public class HttpLoggingInterceptor implements Interceptor { private static final String TAG = "HttpLogging"; private static final Charset UTF8 = StandardCharsets.UTF_8; private volatile Level printLevel = Level.BODY; private java.util.logging.Level colorLevel; private Logger logger; private static boolean prLog; public static void setLog(boolean log) { prLog = log; } public enum Level { NONE, //不打印log BASIC, //只打印 请求首行 和 响应首行 HEADERS, //打印请求和响应的所有 Header BODY //所有数据全部打印 } public HttpLoggingInterceptor(String tag) { logger = Logger.getLogger(tag); colorLevel = java.util.logging.Level.INFO; } public void setPrintLevel(Level level) { if (printLevel == null) throw new NullPointerException("printLevel == null. Use Level.NONE instead."); printLevel = level; } public void setColorLevel(java.util.logging.Level level) { colorLevel = level; } private void log(String message) { //logger.log(colorLevel, message); if (prLog) { // Log.getDynamicLogger(TAG).info(message); System.out.println(message); } //Log.e(TAG,message); } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (request.body() != null && request.body().contentLength() == 0) { val headers = request.headers(); request = chain.call().request().newBuilder() .headers(headers) .build(); } if (printLevel == Level.NONE) { return chain.proceed(request); } //请求日志拦截 logForRequest(request, chain.connection()); //执行请求,计算请求时间 long startNs = System.nanoTime(); Response response; try { response = chain.proceed(request); } catch (Exception e) { log("<-- HTTP FAILED: " + e); throw e; } long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); //响应日志拦截 return logForResponse(response, tookMs); } private void logForRequest(Request request, Connection connection) throws IOException { boolean logBody = (printLevel == Level.BODY); boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS); RequestBody requestBody = request.body(); boolean hasRequestBody = requestBody != null; Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; try { String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol; log(requestStartMessage); if (logHeaders) { if (hasRequestBody) { if (requestBody.contentType() != null) { log("\tContent-Type: " + requestBody.contentType()); } if (requestBody.contentLength() != -1) { log("\tContent-Length: " + requestBody.contentLength()); } } Headers headers = request.headers(); for (int i = 0, count = headers.size(); i < count; i++) { String name = headers.name(i); if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { log("\t" + name + ": " + headers.value(i)); } } log(" "); if (logBody && hasRequestBody) { if (isPlaintext(requestBody.contentType())) { bodyToString(request); } else { log("\tbody: maybe [binary body], omitted!"); } } } } catch (Exception e) { logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); } finally { log("--> END " + request.method()); } } private Response logForResponse(Response response, long tookMs) { Response.Builder builder = response.newBuilder(); Response clone = builder.build(); ResponseBody responseBody = clone.body(); boolean logBody = (printLevel == Level.BODY); boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS); try { log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)"); if (logHeaders) { Headers headers = clone.headers(); for (int i = 0, count = headers.size(); i < count; i++) { log("\t" + headers.name(i) + ": " + headers.value(i)); } log(" "); if (logBody && HttpHeaders.hasBody(clone)) { if (responseBody == null) return response; if (isPlaintext(responseBody.contentType())) { BufferedSource source = responseBody.source(); source.request(Long.MAX_VALUE); // 请求整个流 Buffer buffer = source.buffer(); Charset charset = getCharset(responseBody.contentType()); String body = buffer.clone().readString(charset); log("\tbody:" + body); } else { log("\tbody: maybe [binary body], omitted!"); } } } } catch (Exception e) { logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); } finally { log("<-- END HTTP"); } return response; } private static Charset getCharset(MediaType contentType) { Charset charset = contentType != null ? contentType.charset(UTF8) : UTF8; if (charset == null) charset = UTF8; return charset; } /** * 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. */ private static boolean isPlaintext(MediaType mediaType) { if (mediaType == null) return false; if (mediaType.type() != null && mediaType.type().equals("text")) { return true; } String subtype = mediaType.subtype(); if (subtype != null) { subtype = subtype.toLowerCase(); if (subtype.contains("x-www-form-urlencoded") || subtype.contains("json") || subtype.contains("xml") || subtype.contains("html")) // return true; } return false; } private void bodyToString(Request request) { try { Request copy = request.newBuilder().build(); RequestBody body = copy.body(); if (body == null) return; Buffer buffer = new Buffer(); body.writeTo(buffer); Charset charset = getCharset(body.contentType()); log("\tbody:" + buffer.readString(charset)); // 重置请求体以确保后续处理不受影响 buffer.clear(); } catch (Exception e) { logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); } } }