簡體   English   中英

如何使用NSURLSession確定資源是否已更改?

[英]How to use NSURLSession to determine if resource has changed?

我正在使用NSURLSession從HTTP服務器請求JSON資源。 服務器使用Cache-Control來限制在客戶端上緩存資源的時間。

這很好用,但是我也想在內存中緩存一個反序列化的JSON對象,因為它經常被訪問,同時繼續利用NSURLSession內置的HTTP緩存機制。

我在想可以保存一些HTTP響應標頭: Content-MD5EtagLast-Modified以及反序列化的JSON對象(我使用了這3個字段,因為我注意到並不是所有的HTTP服務器都返回Content-MD5 ,否則就足夠了)。 下次我收到JSON對象的響應時,如果這3個字段相同,則可以重用以前反序列化的JSON對象。

這是確定反序列化JSON仍然有效的可靠方法。 如果不是,如何確定反序列化的對象是否最新?

我創建了一個HTTPEntityFingerprint結構,該結構存儲一些實體頭: Content-MD5EtagLast-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
    }
}

當我得到一個NSHTTPURLResponseNSURLSession ,我創建一個HTTPEntityFingerprint從它並將其與使用預先存儲的指紋HTTPEntityFingerprint.match 如果指紋匹配,則HTTP資源沒有更改,因此我不需要再次反序列化JSON響應; 但是,如果指紋不匹配,那么我反序列化JSON響應並保存新的指紋。

僅當服務器返回以下三個實體頭中的至少一個時,此機制才有效: Content-MD5EtagLast-Modified

有關NSURLSession和NSURLCache行為的更多詳細信息

NSURLSession通過NSURLCache提供的緩存是透明的,這意味着當您請求先前緩存的資源時, NSURLSession將調用完成處理程序/ NSURLSession就像發生200響應一樣。

如果緩存的響應已過期,則NSURLSession將向源服務器發送新請求,但將使用緩存中的Last-ModifiedEtag實體標頭包含If-Modified-SinceIf-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM