最近由于對NSURLRequestCachePolicy設置不當,導致了版本中出現一些bug,特此對NSURLRequestCachePolicy進行了一些研究
NSURLRequestCachePolicy
的定義如下
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad = 2,
NSURLRequestReturnCacheDataDontLoad = 3,
NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
};
NSURLRequestUseProtocolCachePolicy
默認的緩存策略,其行為是由協議指定的針對該協議最好的實現方式。關于該策略的介紹,篇后詳細說明。NSURLRequestReloadIgnoringCacheData
從服務端加載數據,完全忽略緩存。NSURLRequestReturnCacheDataElseLoad
使用緩存數據,忽略其過期時間;只有在沒有緩存版本的時候才從源端加載數據。NSURLRequestReturnCacheDataDontLoad
只使用cache數據,如果不存在cache,請求失敗;用于沒有建立網絡連接離線模式
NSURLRequestUseProtocolCachePolicy實現機制
蘋果官方提供的決策樹如下:
由圖中可以看出,簡單流程如下:
- 如果請求的緩存響應不存在,則URL加載系統直接從源端加載數據;
- 否則,如果緩存響應中沒有明確表示每次請求必須重新驗證,則如果不是響應的緩存過期了,則URL加載系統會返回緩存數據
- 如果緩存的響應過期或者需要重新驗證,URL加載系統發送
HEAD
請求到源端,查看資源是否發生了變化。如果變化了,則URL加載系統取出從始發源的數據。否則,它返回緩存的響應。
緩存的響應過期或者需要重新驗證說明
對于緩存的響應過期或者需要重新驗證的情況,可以通過HTTP中請求和響應頭來判斷
- Cache-Control
在第一次請求到服務器資源的時候,服務器需要使用Cache-Control這個響應頭來指定緩存策略,它的格式如下:Cache-Control:max-age=xxxx,這個頭指指明緩存過期的時間
Cache-Control
頭具有如下選項:
常量 | 意義 |
---|---|
public | 指示響應可被任何緩存區緩存 |
private | 內容只緩存到私有緩存中(僅客戶端可以緩存) |
no-cache | 指示請求或響應消息不能緩存 |
no-store | 所有內容都不會被緩存到緩存或 Internet 臨時文件中 |
must-revalidation | 如果緩存的內容失效,請求必須發送到服務器進行重新驗證 |
max-age | 可以接收生存期不大于指定時間(以秒為單位)的響應 |
min-fresh | 可以接收響應時間小于當前時間加上指定時間的響應 |
max-stale | 可以接收超出超時期間的響應消息 |
Expires
Expires
表示存在時間,允許客戶端在這個時間之前不去檢查(發請求),等同max-age的效果。但是如果同時存在,則被Cache-Control的max-age覆蓋。
格式:Expires = "Expires" ":" HTTP-date"
例如:Expires: Thu, 01 Dec 1994 16:00:00 GMT (必須是GMT格式)Last-Modified/If-Modified-Since
Last-Modified
是由服務器返回響應頭,標識資源的最后修改時間.
If-Modified-Since
則由客戶端發送,標識客戶端所記錄的,資源的最后修改時間。服務器接收到帶有該請求頭的請求時,會使用該時間與資源的最后修改時間進行對比,如果發現資源未被修改過,則直接返回HTTP 304而不返回包體,告訴客戶端直接使用本地的緩存。否則響應完整的消息內容。Etag/If-None-Match
Etag
由服務器發送,告之當資源在服務器上的一個唯一標識符。
客戶端請求時,如果發現資源過期(使用Cache-Control的max-age),發現資源具有Etag聲明,這時請求服務器時則帶上If-None-Match頭,服務器收到后則與資源的標識進行對比,決定返回200或者304。