如何使用NSURLSession来确定资源是否已更改?

Dou*_*son 1 http-headers nsurlcache ios nshttpurlresponse nsurlsession

我正在使用NSURLSession从HTTP服务器请求JSON资源.服务器使用Cache-Control来限制资源缓存在客户端上的时间.

这很好用,但是我还想在内存中缓存一个反序列化的JSON对象,因为它经常被访问,同时继续利用NSURLSession中内置的HTTP缓存机制.

我想我可以保存一些HTTP响应头:Content-MD5,Etag以及Last-Modified反序列化的JSON对象(我使用这3个字段,因为我注意到并非所有HTTP服务器都返回Content-MD5,否则它本身就足够了) .下次我收到JSON对象的响应时,如果这3个字段相同,那么我可以重用以前反序列化的JSON对象.

这是一种确定deserizlied JSON仍然有效的可靠方法.如果没有,我如何确定反序列化的对象是否是最新的?

Dou*_*son 5

我创建了存储的一些实体头的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
    }
}
Run Code Online (Sandbox Code Playgroud)

当我NSHTTPURLResponse从a 获得一个时,我从中NSURLSession创建一个HTTPEntityFingerprint并将其与之前存储的指纹进行比较HTTPEntityFingerprint.match.如果指纹匹配,则HTTP资源没有改变,因此我不需要再次反序列化JSON响应; 但是,如果指纹不匹配,则我反序列化JSON响应并保存新指纹.

这种机制只如果你的服务器返回的3层实体报头中的至少一种工作:Content-MD5,EtagLast-Modified.

有关NSURLSession和NSURLCache行为的更多详细信息

NSURLSessionvia 提供的缓存NSURLCache是透明的,这意味着当您请求先前缓存的资源时,NSURLSession将调用完成处理程序/委托,就好像发生200响应一样.

如果缓存的响应已过期,则NSURLSession将向源服务器发送新请求,但将在缓存(尽管已过期)结果中使用和实体头包含If-Modified-SinceIf-None-Match头.此行为是内置的,除了启用缓存之外,您不必执行任何操作.如果原始服务器返回304(未修改),则将其转换为应用程序的200响应(使其看起来像您获取了资源的新副本,即使它仍然从缓存提供).Last-ModifiedEtagNSURLSession