iOS 網(wǎng)絡(luò)緩存


常見的網(wǎng)絡(luò)數(shù)據(jù)緩存方式

GET網(wǎng)絡(luò)請(qǐng)求緩存

概述

首先要知道,POST請(qǐng)求不能被緩存,只有 GET 請(qǐng)求能被緩存。緩存的思路就是將查詢的參數(shù)組成的值作為 key ,對(duì)應(yīng)結(jié)果作為value。從這個(gè)意義上說(shuō),一個(gè)文件的資源鏈接,也叫 GET 請(qǐng)求

該怎么做?

前提

針對(duì)的是get請(qǐng)求

針對(duì)的是get請(qǐng)求

針對(duì)的是get請(qǐng)求

NSURLCache : NSURLCache 為您的應(yīng)用的 URL 請(qǐng)求提供了內(nèi)存中以及磁盤上的綜合緩存機(jī)制。 作為基礎(chǔ)類庫(kù) URL 加載系統(tǒng) 的一部分,任何通過(guò) NSURLConnection 加載的請(qǐng)求都將被 NSURLCache 處理。個(gè)默認(rèn)緩存在內(nèi)存,并且可以通過(guò)一些配置操作可以持久緩存到磁盤的類。

那么知道了這些之后開始我們的步驟

設(shè)置NSURLCache的大小時(shí),大多使用下面的代碼
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    NSURLCache *urlCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil];
    [NSURLCache setSharedURLCache:urlCache];
}
設(shè)置一個(gè)緩存策略

無(wú)論你是用的是NSURLRequest還是NSMutableURLRequest,你都需要去設(shè)置一下它們的cachePolicy屬性

typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
    NSURLRequestUseProtocolCachePolicy = 0,

    NSURLRequestReloadIgnoringLocalCacheData = 1,
    NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
    NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,

    NSURLRequestReturnCacheDataElseLoad = 2,
    NSURLRequestReturnCacheDataDontLoad = 3,

    NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
}

這些緩存都代表什么意思呢?

NSURLRequestUseProtocolCachePolicy: 對(duì)特定的 URL 請(qǐng)求使用網(wǎng)絡(luò)協(xié)議中實(shí)現(xiàn)的緩存邏輯。這是默認(rèn)的策略。
NSURLRequestReloadIgnoringLocalCacheData:數(shù)據(jù)需要從原始地址加載。不使用現(xiàn)有緩存。
NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不僅忽略本地緩存,同時(shí)也忽略代理服務(wù)器或其他中間介質(zhì)目前已有的、協(xié)議允許的緩存。
NSURLRequestReturnCacheDataElseLoad:無(wú)論緩存是否過(guò)期,先使用本地緩存數(shù)據(jù)。如果緩存中沒(méi)有請(qǐng)求所對(duì)應(yīng)的數(shù)據(jù),那么從原始地址加載數(shù)據(jù)。
NSURLRequestReturnCacheDataDontLoad:無(wú)論緩存是否過(guò)期,先使用本地緩存數(shù)據(jù)。如果緩存中沒(méi)有請(qǐng)求所對(duì)應(yīng)的數(shù)據(jù),那么放棄從原始地址加載數(shù)據(jù),請(qǐng)求視為失?。矗骸半x線”模式)。
NSURLRequestReloadRevalidatingCacheData:從原始地址確認(rèn)緩存數(shù)據(jù)的合法性后,緩存數(shù)據(jù)就可以使用,否則從原始地址加載

知道了它們的意思之后我把工程中加入了下面的代碼

if (![Global shareInstance].isNetReachable) {
            request.cachePolicy = NSURLRequestReturnCacheDataDontLoad;
        }else{
            request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
        }

這樣就做到了當(dāng)網(wǎng)絡(luò)不通時(shí)使用本地緩存。當(dāng)有網(wǎng)絡(luò)是則先使用本地緩存,如果找不到本地緩存就去加載數(shù)據(jù)。
但有些場(chǎng)景下我們的緩存是存在時(shí)效性的。比如商品詳情不同的時(shí)間返回的價(jià)格因?yàn)橛谢顒?dòng)價(jià)已經(jīng)不同了。那么此時(shí)這種辦法就明顯不適用了。

控制緩存的有效性

借助ETag或者Las-Modified判斷文件是否有效

ETag

HTTP協(xié)議規(guī)格說(shuō)明定義ETag為“被請(qǐng)求變量的實(shí)體值”。另一種說(shuō)法是,ETag是一個(gè)可以與Web資源關(guān)聯(lián)的記號(hào)(token)。Web資源可以是一個(gè)web頁(yè)面、json或xml數(shù)據(jù)、文件等。Etag有點(diǎn)類似于文件hash或者說(shuō)是信息摘要。
在瀏覽器默認(rèn)的行為中,當(dāng)進(jìn)行一次URL請(qǐng)求,服務(wù)端會(huì)返回'Etag'響應(yīng)頭,下次瀏覽器請(qǐng)求相同的URL時(shí),瀏覽器會(huì)自動(dòng)將它設(shè)置為請(qǐng)求頭'If-None-Match'的值。服務(wù)器收到這個(gè)請(qǐng)求之后,就開始做信息校驗(yàn)工作將自己本次產(chǎn)生的Etag與請(qǐng)求傳遞過(guò)來(lái)的'If-None-Match'對(duì)比,如果相同,則返回HTTP狀態(tài)碼304,并且response數(shù)據(jù)體中沒(méi)有數(shù)據(jù)。
具體的使用看下面代碼例子

- (void)getData:(GetDataCompletion)completion {
    NSURL *url = [NSURL URLWithString:kETagImageURL];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
    
    // 發(fā)送 etag
    if (self.etag.length > 0) {
        [request setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
    }
    
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        
        // NSLog(@"%@ %tu", response, data.length);
        // 類型轉(zhuǎn)換(如果將父類設(shè)置給子類,需要強(qiáng)制轉(zhuǎn)換)
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"statusCode == %@", @(httpResponse.statusCode));
        // 判斷響應(yīng)的狀態(tài)碼是否是 304 Not Modified (更多狀態(tài)碼含義解釋: https://github.com/ChenYilong/iOSDevelopmentTips)
        if (httpResponse.statusCode == 304) {
            NSLog(@"加載本地緩存圖片");
            // 如果是,使用本地緩存
            // 根據(jù)請(qǐng)求獲取到`被緩存的響應(yīng)`!
            NSCachedURLResponse *cacheResponse =  [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
            // 拿到緩存的數(shù)據(jù)
            data = cacheResponse.data;
        }
        
        // 獲取并且紀(jì)錄 etag,區(qū)分大小寫
        self.etag = httpResponse.allHeaderFields[@"Etag"];
        
        NSLog(@"etag值%@", self.etag);
        !completion ?: completion(data);
    }];
}

Last-Modified

Last-Modified值在服務(wù)器處理階段代表著文件的上次修改時(shí)間,在處理結(jié)束后作為一個(gè)響應(yīng)頭放到response中。如果在請(qǐng)求中添加了'If-Modified-Since'頭,并將這個(gè)值設(shè)置為上次請(qǐng)求時(shí)得到的響應(yīng)頭'Last-Modified'的值,那么這次請(qǐng)求服務(wù)器中邏輯的偽代碼

if ETag != 請(qǐng)求頭中的'If-Non-Match' || 查詢到的'Last-Modified'(上次修改的時(shí)間) != 請(qǐng)求頭中的'If-Modified-Since'
    返回的response狀態(tài)碼200 和 數(shù)據(jù)
else
   返回的reponse狀態(tài)碼304

目前這些也是個(gè)人通過(guò)學(xué)習(xí)網(wǎng)上文章的理解,待之后實(shí)踐后再來(lái)補(bǔ)充詳細(xì)理解。

關(guān)于ETag和Last-Modified的詳細(xì)說(shuō)明可以看下面兩邊詳細(xì)講解


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容