How to use NSURLSession to determine if resource has changed?

依然范特西╮ 提交于 2019-11-28 09:34:13

I created a HTTPEntityFingerprint structure which stores some of the entity headers: Content-MD5, Etag, and 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
    }
}

When I get an NSHTTPURLResponse from an NSURLSession, I create an HTTPEntityFingerprint from it and compare it against a previously stored fingerprint using HTTPEntityFingerprint.match. If the fingerprints match, then the HTTP resource hasn't changed and thus I do not need to deserialized the JSON response again; however, if the fingerprints do not match, then I deserialize the JSON response and save the new fingerprint.

This mechanism only works if your server returns at least one of the 3 entity headers: Content-MD5, Etag, or Last-Modified.

More Details on NSURLSession and NSURLCache Behavior

The caching provided by NSURLSession via NSURLCache is transparent, meaning when you request a previously cached resource NSURLSession will call the completion handlers/delegates as if a 200 response occurred.

If the cached response has expired then NSURLSession will send a new request to the origin server, but will include the If-Modified-Since and If-None-Match headers using the Last-Modified and Etag entity headers in the cached (though expired) result; this behavior is built in, you don't have to do anything besides enable caching. If the origin server returns a 304 (Not Modified), then NSURLSession will transform this to a 200 response the application (making it look like you fetched a new copy of the resource, even though it was still served from the cache).

mkumar

This could be done with simple HTTP standard response.

Assume previous response is something like below:

{ 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;
} }

Now use below to tell server not to send date if it is not modified since.

NSURLSession is a configurable container, you would probably need to use http option "IF-Modified-Since"

Use below configuration kind before downloading the resource,

    NSURLSessionConfiguration *backgroundConfigurationObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"myBackgroundSessionIdentifier"];
    [backgroundConfigurationObject setHTTPAdditionalHeaders:
     @{@"If-Modified-Since": @"Tue, 07 Jul 2015 11:28:46 GMT"}];

if resource for example doesn't change from above set date then below delegate will be called

    - (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
    }

Check the downloadTask.response status code is 304 .. then resource is not modified and the resource is not downloaded.

Note save the previous success full download date in some NSUserDefaults to set it in if-modifed-since

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!