今天同事發(fā)給我這張圖
這是因?yàn)閛khttp中重定向次數(shù)超過(guò)21次以后就會(huì)報(bào)錯(cuò)。
訪問(wèn)一個(gè)接口的時(shí)候?yàn)槭裁磿?huì)重定向,我用finder抓包發(fā)現(xiàn)一切正常,是不是因?yàn)閏ookie宵凌,于是我把瀏覽器cookie一關(guān)。然后瀏覽器也不行了止后。
心想那簡(jiǎn)單瞎惫,給okhttp加上cookie就行了。但是新的問(wèn)題就出現(xiàn)了坯门。如下:
1.第一次打開100%出錯(cuò)
2.退出app微饥,再打開頁(yè)面可以顯示
3.用finder一抓包逗扒,就完全是好的
在接下來(lái)古戴,我發(fā)現(xiàn)訪問(wèn)接口的時(shí)候返回的302地址和接口地址的域名不一樣。例如從a.test.com->b.test.com 我看了一下CookieManger中的代碼矩肩,發(fā)現(xiàn)它管理cookie是通過(guò)host來(lái)作為key的现恼。于是我使用我自己寫的頂級(jí)域名獲取工具,實(shí)現(xiàn)了cookie的跨域傳輸黍檩。然后滿心歡喜的讓大家測(cè)試叉袍。結(jié)果并沒(méi)有什么卵用。
后來(lái)我懷疑是不是一次加載的時(shí)候CookieManager沒(méi)有完成初始化刽酱,所以沒(méi)有獲取到cookie喳逛,于是我打日志發(fā)現(xiàn)第每一次訪問(wèn)接口都是是獲取到cookie的。
實(shí)在是一籌莫展棵里,同事也不清楚這是怎么回事润文。后來(lái)我發(fā)現(xiàn)用finder抓包姐呐,抓出錯(cuò)訪問(wèn)的包,好像抓不到典蝌。我以前覺(jué)得可能是訪問(wèn)太快了曙砂。后來(lái)一想是不是根本就沒(méi)有網(wǎng)絡(luò)請(qǐng)求?
為了證實(shí)我的想法骏掀,我把httpClient.setCache()給注釋掉了鸠澈。
神奇的事情發(fā)生了。居然第一次訪問(wèn)就成功了截驮。于是我得出結(jié)論造成302死循環(huán)的就是——okhttp緩存了重定向頁(yè)面
真相只有一個(gè)那就是:
第一次訪問(wèn)A接口發(fā)生了如下情景:
客戶端對(duì)OkHttp說(shuō):我要A
OKhttp想了想笑陈,我這兒沒(méi)有A,于是說(shuō):我?guī)闳フ褹吧
A說(shuō):你們沒(méi)有登錄葵袭,去找B吧新锈。
OkHttp記住了:找A之前先找B。
OkHttp說(shuō):好眶熬,我去找B了妹笆。
B說(shuō):Cookie給我,我要驗(yàn)證
OkHttp急了:客戶端沒(méi)有給我Cookie呀娜氏。
B面無(wú)表情的說(shuō):我不管 拳缠,你就找A吧 ,我給你開個(gè)證明贸弥。
OkHttp就住了:找B之前要找A窟坐。
于是拿著證明去找A,但是這個(gè)時(shí)候绵疲,A已經(jīng)不是真實(shí)的A了哲鸳,而是
OkHttp記憶中的A,所以O(shè)kHttp想起了A說(shuō)的:找A之前先找B盔憨。
于是OkHttp就去找B徙菠,但是B也是記憶中的B了。而OkHttp不管郁岩,它
只知道B說(shuō)了:給了一個(gè)證明婿奔,先去找A。
于是在OKHttp在腦海中问慎,來(lái)來(lái)回回萍摊。最后人格分裂,報(bào)錯(cuò)了如叼。
最后不能因?yàn)橹囟ㄏ虺鲥e(cuò)就全盤否定OkHttp的緩存功能冰木,所以我在想是不是只要不緩存重定向結(jié)果就OK了
于是我開始Google 百度 研究OkHttp的緩存實(shí)現(xiàn)。終于功夫不負(fù)有心人,我發(fā)現(xiàn)了原來(lái)不是服務(wù)器要求我們要緩存302結(jié)果踊沸,而是我們自作聰明的把所有接口緩存了囚衔,就像這樣的誤人子弟。
于是我在我們模板中加了一句
最后源碼
private class CacheControlInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!AppUtil.getInstance().isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (response != null && response.isRedirect()) {
//如果是重定向雕沿,則不做緩存
return response;
}
if (AppUtil.getInstance().isNetworkConnected()) {
int maxAge = 60; // read from cache for 1 minute
response = response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
response = response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
return response;
}
}
于是OkHttp再也不用再自己的記憶中跑來(lái)跑去了练湿,一切又回到了原點(diǎn)。從此客戶端和服務(wù)器過(guò)上了幸福的生活审轮。