iOS webView緩存有鹿,保證加載最新html

loading.png

iOS webView緩存,保證加載最新html

[TOC]

前言

最近有個需求谎脯,修改webview(WKWebview)加載的緩存機制葱跋。因現(xiàn)在使用的緩存機制是NSURLRequestReturnCacheDataElseLoad(NSURLRequest的緩存機制下面會說到)。這個緩存機制就是只有當本地緩存不存在的時候才會請求源梭,否則加載本地緩存娱俺,這樣就導(dǎo)致當html有所修改的話,下次進入不能主動刷新網(wǎng)頁废麻,還是加載的緩存荠卷,需要手動刷新才能看到最新內(nèi)容。現(xiàn)在的要求就是當:當html過期后(html有修改)烛愧,在下次主動加載html的時候自動加載最新內(nèi)容油宜。

尋找解決方案

1. 查看NSURLRequestAPI

既然之前使用了NSURLRequest的緩存機制,那么首先想到的就是看看有沒有對應(yīng)的緩存機制怜姿。

typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
    NSURLRequestUseProtocolCachePolicy = 0,//默認遵守http緩存策略

    NSURLRequestReloadIgnoringLocalCacheData = 1, //忽略本地緩存
    NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented //忽略本地和遠程緩存
    NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,

    NSURLRequestReturnCacheDataElseLoad = 2,//只有當本地緩存不存在的時候才會請求慎冤,否則加載本地緩存
    NSURLRequestReturnCacheDataDontLoad = 3,//只加載本地緩存,沒有緩存也不會請求

    NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented //判斷緩存是否過期
};

忽略Unimplemented沧卢,可以看到NSURLRequestReloadRevalidatingCacheData不正是我們需要的緩存策略嗎蚁堤?當你高高興興的將緩存策略設(shè)置為NSURLRequestReloadRevalidatingCacheData后,然后加載html但狭,然后修改html內(nèi)容披诗,發(fā)現(xiàn)確實會加載最新的。這個時候你一定會很高心立磁,然而當你打印html加載時間的時候呈队,你會發(fā)現(xiàn)html未修改的情況下和不加載緩存所用的時間都是一樣的,其結(jié)論就是并沒有加載緩存息罗。這個時候你再看Unimplemented就會煥然大悟了掂咒。

所以通過修改NSURLRequest的緩存策略是無法實現(xiàn)該功能的,pass

2. 網(wǎng)上搜索webView的緩存加載策略

通過設(shè)置NSURLRequest的緩存機制無法達到我們的目的迈喉。沒辦法绍刮,只有找其他的方法了。
在查看了很多篇相關(guān)的技術(shù)博客后挨摸,終于找到了一個方法孩革,就是設(shè)置ETag/If-None-MatchLast-Modified/If-Modified-Since來判斷html內(nèi)容是否有更新。其中If-None-MatchIf-Modified-Since是設(shè)置在request headers請求頭中得运,ETagLast-Modifiedresponse headers響應(yīng)頭中膝蜈,由服務(wù)器返回的锅移。

參數(shù)介紹

  • ETag:服務(wù)器驗證令牌,文件內(nèi)容hash饱搏。
  • Last-Modified:響應(yīng)頭標識了資源的最后修改時間非剃。
  • If-None-Match:比較ETag是否一致备绽。
  • If-Modified-Since:比較資源最后修改的時間是否一致。

關(guān)于html的緩存策略可以看看這篇博客鬓催,講的很詳細

基本實現(xiàn)原理

  1. 第一次請求某個html的時候,響應(yīng)頭response headers中會返回ETagLast-Modified(需要html做設(shè)置)宇驾,將其記錄下來倍靡。
  2. 后面每次請求時,在request headers請求頭中設(shè)置If-None-MatchIf-Modified-Since,其中If-None-Match就是記錄的ETag值,If-Modified-Since就是記錄的Last-Modified值。該值會和服務(wù)端的ETagLast-Modified比較。如果相同則返回狀態(tài)碼304娇跟,說明沒有更新,否則返回200,說明需要重新請求。

iOS實現(xiàn)方式

NSURL *url = [NSURL URLWithString:@"http://172.17.124.102:8888/webViewTest.html"];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
    request.HTTPMethod = @"HEAD";
    //獲取記錄的response headers
    NSDictionary *cachedHeaders = [[NSUserDefaults standardUserDefaults] objectForKey:url.absoluteString];
    //設(shè)置request headers
    if (cachedHeaders) {
        NSString *etag = [cachedHeaders objectForKey:@"Etag"];
        if (etag) {
            [request setValue:etag forHTTPHeaderField:@"If-None-Match"];
        }
        NSString *lastModified = [cachedHeaders objectForKey:@"Last-Modified"];
        if (lastModified) {
            [request setValue:lastModified forHTTPHeaderField:@"If-Modified-Since"];
        }
    }
    
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"======= %f",[[NSDate date] timeIntervalSince1970] * 1000);
        // 類型轉(zhuǎn)換
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"statusCode == %@", @(httpResponse.statusCode));
        // 判斷響應(yīng)的狀態(tài)碼
        if (httpResponse.statusCode == 304 || httpResponse.statusCode == 0) {
            //如果狀態(tài)碼為304或者0(網(wǎng)絡(luò)不通?),則設(shè)置request的緩存策略為讀取本地緩存
            [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
        }else {
            //如果狀態(tài)碼為200耐量,則保存本次的response headers,并設(shè)置request的緩存策略為忽略本地緩存钞翔,重新請求數(shù)據(jù)
            [[NSUserDefaults standardUserDefaults] setObject:httpResponse.allHeaderFields forKey:request.URL.absoluteString];
            //如果狀態(tài)碼為200,則設(shè)置request的緩存策略為忽略本地緩存
            [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
        }
        
        //未更新的情況下讀取緩存
        dispatch_async(dispatch_get_main_queue(), ^{
            //判斷結(jié)束之后,修改請求方式东且,加載網(wǎng)頁
            request.HTTPMethod = @"GET";
            [self.webView loadRequest:request];
        });
    }] resume];

在這里启具,我的實現(xiàn)方式是在每次請求加載之前,先獲取html的response headers響應(yīng)頭(使用'HEAD'請求方式珊泳,只獲取'response headers'鲁冯,不獲取頁面)拷沸,通過返回的狀態(tài)碼最終確定其緩存策略是讀取本地緩存還是重新加載。最終達到了預(yù)期的效果薯演。

最后

雖然通過這個方式實現(xiàn)了該功能撞芍,但是在實現(xiàn)過程中還是有一些東西沒有弄懂。
比如:

  1. webView通過loadRequest加載html的時候跨扮,設(shè)置了request headers序无,然后在WKWebView的代理方法webView:didFinishNavigation:方法中獲取的狀態(tài)碼永遠是200response headers響應(yīng)頭在修改了html內(nèi)容后都沒有變化衡创,這里獲取到的數(shù)據(jù)和通過NSURLSession獲取到的有什么不同帝嗡。
    2. 還有就是這種方式獲取狀態(tài)碼response headers響應(yīng)頭其實相當于在加載之前重新請求了一下。 使用HEAD請求可以避免網(wǎng)頁的二次下載璃氢,只請求響應(yīng)頭數(shù)據(jù)哟玷,謝謝王洪亮ios的提醒。

不知道有沒有更好的方法來實現(xiàn)該功能一也,歡迎討論和指正裁僧。

參考博客

  1. http://imweb.io/topic/5795dcb6fb312541492eda8c
  2. https://blog.cnbluebox.com/blog/2015/05/07/architecture-ios-1/
  3. http://www.reibang.com/p/ebcb0a1823be#comment-23319974
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夜牡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚊锹,更是在濱河造成了極大的恐慌最爬,老刑警劉巖镐捧,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诊霹,死亡現(xiàn)場離奇詭異幢泼,居然都是意外死亡,警方通過查閱死者的電腦和手機洁仗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門挨稿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人京痢,你說我怎么就攤上這事∨竦辏” “怎么了祭椰?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疲陕。 經(jīng)常有香客問我方淤,道長,這世上最難降的妖魔是什么蹄殃? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任携茂,我火速辦了婚禮,結(jié)果婚禮上诅岩,老公的妹妹穿的比我還像新娘讳苦。我一直安慰自己带膜,他們只是感情好,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布鸳谜。 她就那樣靜靜地躺著膝藕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咐扭。 梳的紋絲不亂的頭發(fā)上芭挽,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音蝗肪,去河邊找鬼袜爪。 笑死,一個胖子當著我的面吹牛薛闪,可吹牛的內(nèi)容都是我干的辛馆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逛绵,長吁一口氣:“原來是場噩夢啊……” “哼怀各!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起术浪,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瓢对,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胰苏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硕蛹,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年硕并,在試婚紗的時候發(fā)現(xiàn)自己被綠了法焰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡倔毙,死狀恐怖埃仪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陕赃,我是刑警寧澤卵蛉,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站么库,受9級特大地震影響傻丝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诉儒,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一葡缰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦泛释、人聲如沸滤愕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽该互。三九已至,卻和暖如春韭畸,著一層夾襖步出監(jiān)牢的瞬間宇智,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工胰丁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留随橘,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓锦庸,卻偏偏與公主長得像机蔗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子甘萧,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容