初始化 - GateOfTruth/OkSimple GitHub Wiki
oksimple 没有对okhttpclient进行任何的封装,我只创建了一个默认的对象,就像这样
var okHttpClient = OkHttpClient()
所以如果你对okhttpclient有什么特殊处理,诸如connectTimeout,protocols,cookiejar,eventlistener,拦截器等,建议在application中对其进行初始化,就像这样
OkSimple.okHttpClient=OkHttpClient.Builder().addInterceptor(logInterceptor)
.connectTimeout(100,TimeUnit.SECONDS)
.writeTimeout(100,TimeUnit.SECONDS)
.readTimeout(100,TimeUnit.SECONDS)
.cache(Cache(cacheDir,1024*1024*10))
.cookieJar(object :CookieJar{
override fun loadForRequest(url: HttpUrl): List<Cookie> {
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
}
})
.eventListener(object :EventListener(){
override fun dnsStart(call: Call, domainName: String) {
}
})
.build()
关于缓存,okhttp框架本身就对缓存做了相应处理,只需要后端返回正确的header,okhttp的缓存就可以正常工作。因此,我没有像其他一些框架一样,重新写一遍缓存。对此有疑问的可以看一下我翻译的这篇文章
oksimple默认会在没有网络的情况下,添加force cache。也就是说你可以不用再写这样的拦截器了,因为这个功能已经实现了。
//不需要再写这样的拦截器,这个功能已经内置了
public class ForceCacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
if (!NetworkUtils.internetAvailable()) {
builder.cacheControl(CacheControl.FORCE_CACHE);
}
return chain.proceed(builder.build());
}
}
okHttpClient.addInterceptor(new ForceCacheInterceptor());
要开启这个功能,需要在你的application里初始化oksimple用到的application
OkSimple.application=this//this指代你的application
默认添加force cache这个功能也是可以控制的
OkSimple.networkUnavailableForceCache=true//默认为true,当为false时,则不会在断网的时候添加force cache。
如果你一开始就不打算使用这个功能,那么你就不要初始化oksimple用到的application。也就是说要开启在断网情况下添加force cache这个功能,需要满足两个条件,第一个是给oksimple用到的application赋值,第二个是networkUnavailableForceCache为true(虽然它本身默认就是true)。
全局参数的话,诸如各种渠道参数等,或者全局的header,诸如token等,可以分别调用
OkSimple.addGlobalParams("key","value")
和
OkSimple.addGlobalHeader("key","value")
你可以在任何地方调用这两个方法,都会生效,如果你想对这些参数进行一些操作,那么直接获取OkSimple.globalHeaderMap和OkSimple.globalParamsMap即可。
//取消某个请求
OkSimple.cancelCall(tag)
//取消所有请求
OkSimple.cancelAll()
取消单个请求需要传入当前请求的tag。tag是有默认值的,tag的默认值等于当前请求的url。需要注意的是,当前url是.get或.post等方法里的url,也就是说,不包括params()方法和addGlobalParams()方法添加的参数。之后在其他地方提到的url都是如此,就不再赘述。你也可以调用settag方法,配置自定义tag。
Oksimple默认会防止重复请求,也就是当你向服务器发出一个请求的时候,如果服务器没有返回结果,无论这个结果是成功,失败或者超时,都会对之后的同一个请求进行拦截,之后的请求,不会发送到服务器,直到当前请求有了返回。而判断是否是同一个请求,是根据tag(tag的默认值是url),参数字符串,和请求长度来综合判断来进行判断的。防止重复请求的开关是
OkSimple.preventContinuousRequests=false//默认为false,当为true时,则会防止重复请求
当开关开启的时候,是可以有效防止诸如用户狂点按钮,导致短时间发送多个请求的情况发生的。这个功能的逻辑是相同的请求同时发起的时候,多余的请求会被拦截,直到上一个请求成功或者失败。
被拦截的请求,如果是异步请求,会回调ResultCallBack的requestAbandon方法,并在会在控制台打印error级别的log。当然,你也可以对这个方法进行重写。如果是同步请求,会在BaseSynchronizeBean的exception里看到一个RuntimeException,描述也是:Same Request!!! This request has been abandoned!!!
注意事项: 除了post和get请求,其他的请求,诸如HEAD,PUT,DELETE等,即使把preventContinuousRequests设置为true也不会进行重复请求的判断和拦截。主要是这几个请求没有进行单独处理,本着宁愿多请求也不漏请求的原则,所以这几种类型的请求,是不会被拦截的。
根据change log,从okhttp 4.1开始,okhttp开始支持Brotli压缩。关于Brotli和gzip的区别,可以去看这篇文章,大致就是说Brotli改变了编码方式,可以相比gzip达到更高的压缩率,减少37%的延迟。要用的话需要单独导入
implementation 'com.squareup.okhttp3:okhttp-brotli:4.x'//和okhttp版本相同
然后在代码里这样使用
OkHttpClient.Builder().addInterceptor(BrotliInterceptor)
注意BrotliInterceptor是单例模式的,在java里也按单例的用法使用就行了。有人会问,为啥是addInterceptor而不是addNetworkInterceptor,这里我放部分源码,你应该就理解了
//这是okhttp RealCall的部分源码
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
//这是BridgeInterceptor里的源码
var transparentGzip = false
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true
requestBuilder.header("Accept-Encoding", "gzip")
}
//这是BrotliInterceptor的源码
if (chain.request().header("Accept-Encoding") == null) {
val request = chain.request().newBuilder()
.header("Accept-Encoding", "br,gzip")
.build()
val response = chain.proceed(request)
uncompress(response)
} else {
chain.proceed(chain.request())
}
所以原因就恨明显了,okhttp会先走BridgeInterceptor导致你的Accept-Encoding不为null,如果你放在networkInterceptors的话,BrotliInterceptor发现你已经有了Accept-Encoding,则不会在Accept-Encoding里添加br。添加br的意思就是像服务器请求使用Brotli压缩。
但是不管是gzip还是brotli,都是需要发送和接收的双方都能够压缩和解压。android手机既可以是发送方也可以是接收方,服务器同理。假如其中一方不支持Brotli压缩的话,则一切也就无从谈起了。
所以我们可以看到BrotliInterceptor在Accept-Encoding放了两个字段,当服务器端不支持Brotli压缩的时候,可以使用gzip压缩。目前来说,支持Brotli压缩的网站还是比较少的。
代码里有个BrotliActivity,是示范用,表示原本不使用br压缩的,可以在某一时刻开启br压缩。