如何使用NSURLSession来确定资源是否已更改? [英] How to use NSURLSession to determine if resource has changed?

查看:197
本文介绍了如何使用NSURLSession来确定资源是否已更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using NSURLSession to request a JSON resource from an HTTP server. The server uses Cache-Control to limit the time the resource is cached on clients.

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

This works great, but I'd also like to cache a deserialized JSON object in memory as it is accessed quite often, while continuing to leverage the HTTP caching mechanisms built into NSURLSession.

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

I'm thinking I can save a few HTTP response headers: Content-MD5, Etag, and Last-Modified along with the deserialized JSON object (I'm using those 3 fields since I've noticed not all HTTP servers return Content-MD5, otherwise that'd be sufficient by itself). The next time I receive a response for the JSON object, if those 3 fields are the same then I can reuse the previously deserialized JSON object.

这是一种强有力的方式确定deserizlied JSON仍然有效。如果没有,我如何确定反序列化的对象是否是最新的?

Is this a robust way to determine the deserizlied JSON is still valid. If not, how do I determine if the deserialized object is up to date?

推荐答案

I创建了一个HTTPEntityFingerprint结构,用于存储一些实体头: Content-MD5 Etag Last-Modified

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

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

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.

此机制仅在您的服务器返回3中的至少一个时才有效实体标题: Content-MD5 Etag ,或 Last-Modified

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

提供的缓存NSURLSession 通过 NSURLCache 是透明的,这意味着当您请求以前缓存的资源 NSURLSession 将调用完成处理程序/委托,好像发生了200响应。

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.

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

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).

这篇关于如何使用NSURLSession来确定资源是否已更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆