![](/img/trans.png)
[英]How to accurately determine day has changed with UIApplicationSignificantTimeChange?
[英]How to use NSURLSession to determine if resource has changed?
我正在使用NSURLSession從HTTP服務器請求JSON資源。 服務器使用Cache-Control來限制在客戶端上緩存資源的時間。
這很好用,但是我也想在內存中緩存一個反序列化的JSON對象,因為它經常被訪問,同時繼續利用NSURLSession內置的HTTP緩存機制。
我在想可以保存一些HTTP響應標頭: Content-MD5
, Etag
和Last-Modified
以及反序列化的JSON對象(我使用了這3個字段,因為我注意到並不是所有的HTTP服務器都返回Content-MD5
,否則就足夠了)。 下次我收到JSON對象的響應時,如果這3個字段相同,則可以重用以前反序列化的JSON對象。
這是確定反序列化JSON仍然有效的可靠方法。 如果不是,如何確定反序列化的對象是否最新?
我創建了一個HTTPEntityFingerprint結構,該結構存儲一些實體頭: Content-MD5
, Etag
和Last-Modified
。
import Foundation
struct HTTPEntityFingerprint {
let contentMD5 : String?
let etag : String?
let lastModified : String?
}
extension HTTPEntityFingerprint {
init?(response : NSURLResponse) {
if let httpResponse = response as? NSHTTPURLResponse {
let h = httpResponse.allHeaderFields
contentMD5 = h["Content-MD5"] as? String
etag = h["Etag"] as? String
lastModified = h["Last-Modified"] as? String
if contentMD5 == nil && etag == nil && lastModified == nil {
return nil
}
} else {
return nil
}
}
static func match(first : HTTPEntityFingerprint?, second : HTTPEntityFingerprint?) -> Bool {
if let a = first, b = second {
if let md5A = a.contentMD5, md5B = b.contentMD5 {
return md5A == md5B
}
if let etagA = a.etag, etagB = b.etag {
return etagA == etagB
}
if let lastA = a.lastModified, lastB = b.lastModified {
return lastA == lastB
}
}
return false
}
}
當我得到一個NSHTTPURLResponse
從NSURLSession
,我創建一個HTTPEntityFingerprint
從它並將其與使用預先存儲的指紋HTTPEntityFingerprint.match
。 如果指紋匹配,則HTTP資源沒有更改,因此我不需要再次反序列化JSON響應; 但是,如果指紋不匹配,那么我反序列化JSON響應並保存新的指紋。
僅當服務器返回以下三個實體頭中的至少一個時,此機制才有效: Content-MD5
, Etag
或Last-Modified
。
NSURLSession
通過NSURLCache
提供的緩存是透明的,這意味着當您請求先前緩存的資源時, NSURLSession
將調用完成處理程序/ NSURLSession
就像發生200響應一樣。
如果緩存的響應已過期,則NSURLSession將向源服務器發送新請求,但將使用緩存中的Last-Modified
和Etag
實體標頭包含If-Modified-Since
和If-None-Match
標頭(盡管已過期)結果; 這種行為是內置的,除了啟用緩存之外,您無需執行任何其他操作。 如果原始服務器返回304(未修改),則NSURLSession
會將其轉換為應用程序響應200(使它看起來像您獲取了資源的新副本,即使仍從緩存中獲取了該資源)。
這可以通過簡單的HTTP標准響應來完成。
假定先前的響應如下所示:
{ status code: 200, headers {
"Accept-Ranges" = bytes;
Connection = "Keep-Alive";
"Content-Length" = 47616;
Date = "Thu, 23 Jul 2015 10:47:56 GMT";
"Keep-Alive" = "timeout=5, max=100";
"Last-Modified" = "Tue, 07 Jul 2015 11:28:46 GMT";
Server = Apache;
} }
現在,使用下面的命令告訴服務器如果以后未對其進行修改,則不要發送日期。
NSURLSession
是可配置的容器,您可能需要使用http選項“ IF-Modified-Since”
下載資源之前,請使用以下配置類型,
NSURLSessionConfiguration *backgroundConfigurationObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"myBackgroundSessionIdentifier"];
[backgroundConfigurationObject setHTTPAdditionalHeaders:
@{@"If-Modified-Since": @"Tue, 07 Jul 2015 11:28:46 GMT"}];
如果例如資源從設定的日期起沒有發生變化,則將在以下委托下調用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) downloadTask.response;
if([httpResponse statusCode] == 304)
//resource is not modified since last download date
}
檢查downloadTask.response
狀態代碼為304 ..則未修改資源且未下載資源。
注意將以前的成功完整下載日期保存在某些NSUserDefaults
以將其設置為if-modifed-since
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.