常見(jiàn)的網(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)求視為失敗(即:“離線”模式)怯伊。
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ì)講解