由于测试、后端人员要求,需要在测试的时候随时查看请求日志。故写下此配置,记录一下 class NetWorkConsoleUtil private constructor() { private val TAG = NetWorkConsoleUtil::class.java.simpleName private val OMITTED_RESPONSE: String = "response body type:" private val OMITTED_REQUEST: String = "request body type:" private val UTF8 = Charset.forName("UTF-8") private lateinit var netLogList: MutableList<String> private lateinit var sensorTrackList: MutableList<String> init { if (!this::netLogList.isInitialized) { netLogList = mutableListOf() } if (!this::sensorTrackList.isInitialized) { sensorTrackList = mutableListOf() } } companion object { val INSTANCE: NetWorkConsoleUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { NetWorkConsoleUtil() } } fun setSensorTrackLogInfo(trackSaId: String){ if (this::sensorTrackList.isInitialized) { if (sensorTrackList.size >= 100){ for (index in 0 until 50){ sensorTrackList.removeAt(index) } } sensorTrackList.add(trackSaId) } } /** * 尽量使用流的形式拿取请求体、响应体,避免连接被关闭 */ fun setNetLogsInfo(request: Request, response: Response){ val requestBody = request.body var body: String? = null if (requestBody != null) { val buffer = Buffer() requestBody.writeTo(buffer) var charset: Charset? = UTF8 val contentType = requestBody.contentType() if (contentType != null) { if (isNotFileRequest(contentType.subtype)) { charset = contentType.charset(UTF8) body = JsonFormaterUtil.format(buffer.readString(charset!!)) } else { body = OMITTED_REQUEST+contentType.subtype } //解决\n,\t,\r在html文本中不起作用的问题 if (!TextUtils.isEmpty(body)) { body = body?.replace("\n", "<br/>") body = body?.replace("\t", " ") } } } val requestHtmlStr = "<b><font size=\"3\" color=\"#FF9200\">发送请求:</font></b> <br/> " + "<font color=\"blue\">method: </font>${request.method} <br/> " + "<font color=\"blue\">url: </font>${request.url} <br/> " + "<font color=\"blue\">headers: </font>${request.headers} <br/> " + "<font color=\"blue\">body: </font>${body ?: "requestBody is null"} <br/>" val responseBody = response.body var rBody: String? = null if (requestBody != null) { val source = responseBody?.source() source?.request(java.lang.Long.MAX_VALUE) val buffer = source?.buffer() var charset = UTF8 val contentType = responseBody?.contentType() if (contentType != null) { if(isNotFileRequest(contentType.subtype)) { try { charset = contentType.charset(UTF8) } catch (e: UnsupportedCharsetException) { e.printStackTrace() } rBody = JsonFormaterUtil.format(buffer?.clone()?.readString(charset)) } else { rBody = OMITTED_RESPONSE+contentType.subtype } //解决\n,\t,\r在html文本中不起作用的问题 if (!TextUtils.isEmpty(rBody)) { rBody = rBody?.replace("\n", "<br/>") rBody = rBody?.replace("\t", " ") } } } val responseHtmlStr = "<b><font size=\"3\" color=\"#FF9200\">收到响应:</font></b> <br/> " + "<font color=\"blue\">status:</font>${response.code} " + "<br/> <font color=\"blue\">body: </font>${rBody ?: "responseBody is null"}" if (this::netLogList.isInitialized) { if (netLogList.size >= 100){ for (index in 0 until 50){ netLogList.removeAt(index) } } netLogList.add(requestHtmlStr + responseHtmlStr) } } /** * 判断是不是文件流类的传输 * true(不是),false(是或者传输类型获取不到) */ private fun isNotFileRequest(subtype: String?): Boolean { return subtype != null && (subtype.contains("json") || subtype.contains("xml") || subtype.contains("plain") || subtype.contains("html")) } fun getNetLogList(): MutableList<String> = netLogList fun getSensorTrackLogList(): MutableList<String> = sensorTrackList }
NetWorkConsoleUtil就是收集以及格式化数据的帮助类,收集好后直接在需要展示的界面上展示,setNetLogsInfo(request: Request, response: Response)两个参数分别是在okhttp自定义拦截器中获取到请求体Request、响应体Response。
其中用到的JsonFormaterUtil类如下:
public class JsonFormaterUtil { public static String format(String jsonStr){ try { ByteArrayInputStream in = new ByteArrayInputStream(jsonStr.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); char ch; int read; int space=0; while((read = in.read()) > 0){ ch = (char)read; switch (ch){ case '{': { space = outputAndRightMove(space, ch, out); break; } case '[': { out.write(ch); space += 2; break; } case '}': { space = outputAndLeftMove(space, ch, out); break; } case ']': { space = outputAndLeftMove(space, ch, out); break; } case ',': { out.write(ch); outputNewline(out); out.write(getBlankingStringBytes(space)); break; } default: { out.write(ch); break; } } } return out.toString(); } catch (IOException e){ e.printStackTrace(); } return null; } private static int outputAndRightMove(int space, char ch, ByteArrayOutputStream out) throws IOException { //换行 outputNewline(out); //向右缩进 out.write(getBlankingStringBytes(space)); out.write(ch); outputNewline(out); space += 2; //再向右缩进多两个字符 out.write(getBlankingStringBytes(space)); return space; } private static int outputAndLeftMove(int space, char ch, ByteArrayOutputStream out) throws IOException{ outputNewline(out); space -= 2; out.write(getBlankingStringBytes(space)); out.write(ch); return space; } private static byte[] getBlankingStringBytes(int space){ StringBuilder sb = new StringBuilder(""); for (int i = 0; i < space; i++) { sb.append("\t"); } return sb.toString().getBytes(); } private static void outputNewline(ByteArrayOutputStream out){ out.write('\n'); } }