okhttp添加日志拦截器,上传文件RequestBody.writeTo调用两次
Posted 威威dett
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了okhttp添加日志拦截器,上传文件RequestBody.writeTo调用两次相关的知识,希望对你有一定的参考价值。
okhttp添加日志拦截器,上传文件RequestBody.writeTo调用两次
在使用okhttp上传文件监听进度时,由于OkHttpClient添加了日志拦截器,会导致RequestBody.writeTo调用2次的问题,网上找了好多,浪费好多时间,也没有找到合适的…
废话不多说,下面介绍2种解决方法,最后面分析调用2次的原因和解决思路
方法一:
在添加日志拦截器的时候,控制是否打印日志,如:在上传文件时设置
HttpLoggingInterceptor.Level.NONE
再或者,粗暴点,就直接在上传文件的时候,重新创建一个OkHttpClient实体删掉HttpLoggingInterceptor就行了
OkHttpClient.Builder builder = new OkHttpClient.Builder().
connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS)
.readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS)
.writeTimeout(WRITE_TIME_OUT, TimeUnit.MILLISECONDS)
.addInterceptor(new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.NONE));
这样就可以调用一次了,但是这样就需要在上传文件的时候单独配置一个OkHttpClient实体,无法公用同一个OkHttpClient,有没有什么更优雅的方法呢,下面介绍第二种
方法二:
在监听进度的的RequestBody
中重写isOneShot
函数法返回值为true
就行了(默认false
)
如:我定义的一个监听进度的类
public class ProgressRequestBody<T> extends RequestBody
// 省略代码....
@Override
public boolean isOneShot()
// 此处返回true,防止添加了日志拦截器导致,
// 上传文件时writeTo函数2次调用(因为日志拦截器里面也调用了一次)
return true;
// 省略代码....
isOneShot
函数的官方解释:https://square.github.io/okhttp/4.x/okhttp/okhttp3/-request-body/is-one-shot/
好了,到这里2中方式都介绍完了
下面介绍一下原因,下面是我贴的HttpLoggingInterceptor 4.0的部分源码,主要由于打印日志的时候里面有调用requestBody.writeTo(buffer),解决思路我都写在下面代码的注释里面了
// 官方源码
class HttpLoggingInterceptor @JvmOverloads constructor(
private val logger: Logger = Logger.DEFAULT
) : Interceptor
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response
val level = this.level
// 第一种
// 这里,就是我们介绍的第一种方法的思路,设置Level.NONE
// 直接return掉了,不会走下面的 requestBody.writeTo(buffer)
// 也就避免了2次调用的情况
val request = chain.request()
if (level == Level.NONE)
return chain.proceed(request)
val logBody = level == Level.BODY
val logHeaders = logBody || level == Level.HEADERS
val requestBody = request.body
if (!logBody || requestBody == null)
logger.log("--> END $request.method")
else if (bodyHasUnknownEncoding(request.headers))
logger.log("--> END $request.method (encoded body omitted)")
else if (requestBody.isDuplex())
logger.log("--> END $request.method (duplex request body omitted)")
else if (requestBody.isOneShot())
// 第二种,根据官方注释,此处 isOneShot返回true时,就可走到这里,防止进入到下面的
// else分支里面执行requestBody.writeTo(buffer)
logger.log("--> END $request.method (one-shot body omitted)")
else
// 根源:由于我们自定义监听进度的时候回调用一次requestBody.writeTo,
// 这里再次调用了,导致调用2次
val buffer = Buffer()
requestBody.writeTo(buffer)
好了,到此RequestBody.writeTo
调用两次的问题和原因都分析完了,如果对你有用,欢迎给个免费的赞
以上是关于okhttp添加日志拦截器,上传文件RequestBody.writeTo调用两次的主要内容,如果未能解决你的问题,请参考以下文章
Retrofit2.0+OkHttp打印Request URL(请求地址参数)
Retrofit2.0+OkHttp打印Request URL(请求地址参数)
Retrofit2.0+OkHttp打印Request URL(请求地址参数)