日志采集是一个APP必备的功能,可以方便开发人员快速定位问题,解决问题,那么我们在使用okhttp的时候应该怎样添加日志功能呢?
直接上干货
private class LogInterceptor implements Interceptor {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Log.v(TAG, "request:" + request.toString());
long t1 = System.nanoTime();
okhttp3.Response response = chain.proceed(chain.request());
long t2 = System.nanoTime();
Log.v(TAG, String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
okhttp3.MediaType mediaType = response.body().contentType();
String content = response.body().string();
Log.i(TAG, "response body:" + content);
return response.newBuilder()
.body(okhttp3.ResponseBody.create(mediaType, content))
.build();
}
}
...
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new LogInterceptor())
.build();
首先我们实现了一个拦截器LogInterceptor
,里面做了三件事情:打印request内容->执行request->打印response内容,过程简单清晰。但是有一个地方需要注意一下,在调用了response.body().string()
方法之后,response中的流会被关闭,我们需要创建出一个新的response给应用层处理通过。手快的同学已经敲完了代码并验证了一遍,发现拦截器中能获取到body的内容,但是在拦截器外面就获取不到了。response.peekBody()
方法复制了一个ResponseBody,使用这个临时的ResponseBody来打印body的内容,而不是直接使用response.body().string()
(此方法在header的content-length不确定的情况下会出错,感谢苦逼键盘男kkmike999的指正)
这是为什么呢?Talk is cheap show me the code。先看一下response.body().string()
的实现
public final String string() throws IOException {
return new String(bytes(), charset().name());
}
string()
调用了bytes()
来获取内容
public final byte[] bytes() throws IOException {
//省略部分代码
BufferedSource source = source();
byte[] bytes;
try {
bytes = source.readByteArray();
} finally {
Util.closeQuietly(source);
}
//省略部分代码
return bytes;
}
在bytes()
方法中先得到了BufferedSource
,然后将BufferedSource
中的内容读取出来,最后将BufferedSource
中的文件流关闭,似乎并没有什么问题。等等,我们在拦截器中将BufferedSource
中的文件流关闭,而在ResponseBody中没有相应的数据缓存,所以我们在拦截器外部再想获取body的内容就失败了,一切终于真相大白。
可以看到,我们在拦截器中相当于手动处理了网络请求的整个过程,这就意味着在拦截器中可以做非常多的事情,例如虚拟一个返回结果等等,这些就不是本文的内容了。
Update
使用Logging Interceptor可以很轻松的实现日志采集功能,具体细节参考
参考内容:
[1]. https://github.com/square/okhttp/wiki/Interceptors