How to use NSURLSession to determine if resource has changed?(如何使用 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.
这是确定反序列化 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?
推荐答案
我创建了一个 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 来判断资源是否发生了变化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何使用 NSURLSession 来判断资源是否发生了变化?
基础教程推荐
- 在 iOS 7 下 CCMenu 错位 2022-01-01
- EditText 中的 setHintTextColor() 2022-01-01
- 在视图控制器的宽度上水平均匀分布 UIButton 的最简单方法? 2022-01-01
- 从 UIWebView 访问元数据 2022-01-01
- UINavigationItem 的持久 rightBarButtonItem 属性 2022-01-01
- 更改 UITableView 部分标题的颜色 2022-01-01
- Firebase 云消息传递令牌未生成 2022-01-01
- UINavigationBar 隐藏按钮文本 2022-01-01
- Android - 如何在runOnUiThread 中将数据传递给Runnable? 2022-01-01
- iOS4 创建后台定时器 2022-01-01