背景
最近關(guān)于web界面偶有反饋拉到舊的界面股冗,導(dǎo)致出現(xiàn)一些異常情況;
因此和蚪,對web資源的加載止状、緩存進(jìn)行一些梳理。
正文
一攒霹、緩存相關(guān)概念介紹
NSURLCache是iOS系統(tǒng)常用的web緩存方式怯疤,通過
[NSURLCache sharedURLCache]
獲取默認(rèn)的緩存相關(guān)信息;可以在啟動的時候催束,通過[NSURLCache setSharedURLCache:URLCache]
的方式設(shè)置一個自定義的NSURLCache集峦。NSCache和NSURLCache名字相近,其實(shí)沒有什么關(guān)系抠刺;NSCache可以認(rèn)為是一個字典緩存塔淤,在內(nèi)存不足的時候會自動釋放對象。雖然是系統(tǒng)提供的官方緩存類速妖,但是實(shí)際開發(fā)中并沒有使用凯沪,替代者是YYCache。
URLProtocol是iOS系統(tǒng)對URL請求行為進(jìn)行抽象买优,細(xì)化出每一步操作妨马,讓開發(fā)者可以針對每一步進(jìn)行代理挺举,實(shí)現(xiàn)對特定請求的攔截,并返回本地的數(shù)據(jù)烘跺。
使用的時候湘纵,首先通過canInitWithRequest:(NSURLRequest *)request
,告訴系統(tǒng)要進(jìn)行代理滤淳;
然后在startLoading
中梧喷,通過判斷request和本地緩存信息,判斷本次請求是否可以返回本地數(shù)據(jù)脖咐,并相應(yīng)調(diào)用client的方法铺敌;
舉例,下面就是讀取本地數(shù)據(jù)屁擅,判斷ETag是否相同偿凭,進(jìn)而返回304的邏輯:
NSString *requestETag = request.allHTTPHeaderFields[@"If-None-Match"];
NSString *etag = localData.eTag?:@"";
NSDictionary *headerFields = @{@"Cache-Control" : @"max-age=600", @"ETag":etag, @"Access-Control-Allow-Origin" : @"*"};
if (requestETag.length > 0 && [requestETag isEqualToString:etag]) {
NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:304 HTTPVersion:nil headerFields:headerFields];
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
[self.client URLProtocolDidFinishLoading:self];
}
NSURLCache和URLProtocol的差別:
1、NSURLCache只支持GET請求派歌,URLProtocol還支持Post請求弯囊;
2、NSURLCache清理緩存通常使用removeAllCachedResponses清理全部緩存胶果,URLProtocol是代理資源加載過程匾嘱,本地磁盤的資源存儲由業(yè)務(wù)控制;
二早抠、HTTP的緩存機(jī)制
以某個web界面加載為例霎烙,當(dāng)我們不使用瀏覽器緩存時,返回的response是完整的html文本蕊连,同時還附帶著ETag吼过;
如果打開緩存策略,則請求頭帶了If-None-Match(對應(yīng)直接的ETag: "5e58f3dd-b0b")咪奖,此時回包體積明顯變小,同時返回碼是304酱床;
當(dāng)請求或者response帶有no-cache羊赵、max-age=0時,緩存的資源仍可使用扇谣,但是會通過請求進(jìn)行驗(yàn)證昧捷,類似上面的ETag,返回304表示Not Modified罐寨,可以繼續(xù)使用靡挥;(no-cache,并非放棄緩存)
而當(dāng)max-age=3600時鸯绿,表示資源有效時間是1個小時跋破,在有效時間內(nèi)不需要通過后端驗(yàn)證簸淀,此時不需要發(fā)起網(wǎng)絡(luò)請求,會直接由cache返回數(shù)據(jù)毒返。(前提是客戶端的request的header租幕,沒有設(shè)置no-cache和max-age=0)
一個資源的請求流程:
關(guān)于request和response的總結(jié):
- request的header是資源請求的核心控制參數(shù)拧簸,如果request的cache策略是no-cache或者max-age=0劲绪,則一定會驗(yàn)證資源;
- request沒有設(shè)置cache-control的策略盆赤,則按照response的策略進(jìn)行贾富,如果age大于reponse的max-age或者response設(shè)置了no-cache,則會進(jìn)行資源校驗(yàn)牺六;如果reponse設(shè)置了max-age=x颤枪,客戶端的age當(dāng)前小于x,則不會發(fā)起網(wǎng)絡(luò)請求兔乞,直接使用cache的數(shù)據(jù)汇鞭;
web同學(xué)表示,web界面通常不會設(shè)置request的cache-control庸追,因?yàn)殪o態(tài)資源的加載永遠(yuǎn)在js之前霍骄;
即使是在html的最前面加上cache-control的<meta>標(biāo)簽,也是在html拉到之后才能生效淡溯;
(但是客戶端開發(fā)可以設(shè)置request-header)
三读整、業(yè)務(wù)緩存邏輯(web緩存SDK)
在前面的client->cache->server基礎(chǔ)上,web緩存SDK所在的層級是在cache和server之間咱娶;
cache屬于瀏覽器自身的緩存米间,web緩存SDK相當(dāng)于代理,阻斷了瀏覽器發(fā)起的網(wǎng)絡(luò)請求膘侮,如果本地有匹配的數(shù)據(jù)屈糊,則使用本地數(shù)據(jù)返回,如果沒有使用網(wǎng)絡(luò)請求琼了,最終所有的數(shù)據(jù)都會加載到cache逻锐;
web緩存SDK和上面的緩存策略并沒有關(guān)系,上面的緩存策略決定是否要發(fā)起網(wǎng)絡(luò)請求去驗(yàn)證資源雕薪、加載資源昧诱,而web緩存SDK則是在請求發(fā)起之后直接返回,類似charles的map local所袁;
四盏档、一個歷史教訓(xùn)
線上的web界面出現(xiàn)一個bug,web的同學(xué)修復(fù)完之后燥爷,手動刷新了cdn的資源和業(yè)務(wù)緩存SDK的資源蜈亩。
但是部分html配置的no-cache失效(設(shè)置了max-age=xxx)懦窘,導(dǎo)致如果之前進(jìn)入過在拉到之前,會使用瀏覽器緩存勺拣;導(dǎo)致本次啟動會一直使用舊的的界面奶赠。
解決方案:
1、更換該界面的url药有,使得cache失效毅戈;
2、清除webKit的緩存愤惰;
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate dateWithTimeIntervalSince1970:0] completionHandler:^{
//清除靜態(tài)資源成功
}];
總結(jié)
HTTP協(xié)議的學(xué)問博大精深苇经,這次借此對緩存相關(guān)知識進(jìn)行一次梳理。
如有紕漏宦言,歡迎指正扇单;如有關(guān)于緩存的使用建議,歡迎交流奠旺。
參考鏈接
https://stackoverflow.com/questions/27105094/how-to-remove-cache-in-wkwebview