我使用NSURLSession从HTTP服务器请求JSON资源。服务器使用Cache-Control来限制资源缓存在客户端上的时间。
这很好用,但是我也喜欢在内存中缓存一个反序列化的JSON对象,因为它经常被访问,同时继续利用NSURLSession中内置的HTTP缓存机制。
我认为我可以保存一些HTTP响应标头:Content-MD5
,Etag
和Last-Modified
以及反序列化的JSON对象(我使用那些3个字段,因为我注意到并非所有HTTP服务器都返回Content-MD5
,否则它本身就足够了)。下次我收到JSON对象的响应时,如果这3个字段相同,那么我可以重用以前反序列化的JSON对象。
这是一种确定deserizlied JSON仍然有效的可靠方法。如果没有,我如何确定反序列化的对象是否是最新的?
答案 0 :(得分: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
}
}
当我从NSHTTPURLResponse
获得NSURLSession
时,我会从中HTTPEntityFingerprint
创建HTTPEntityFingerprint.match
并使用Content-MD5
将其与先前存储的指纹进行比较。如果指纹匹配,则HTTP资源没有改变,因此我不需要再次反序列化JSON响应;但是,如果指纹不匹配,那么我反序列化JSON响应并保存新指纹。
此机制仅在您的服务器至少返回3个实体标头中的一个时才有效:Etag
,Last-Modified
或NSURLSession
。
NSURLCache
通过NSURLSession
提供的缓存是透明的,这意味着当您请求以前缓存的资源If-Modified-Since
时,将调用完成处理程序/委托,就像发生200响应一样。
如果缓存的响应已过期,则NSURLSession将向源服务器发送新请求,但会使用If-None-Match
和Last-Modified
包含Etag
和NSURLSession
标头缓存(虽然已过期)结果中的实体标头;此行为是内置的,除了启用缓存之外,您不必执行任何操作。如果原始服务器返回304(未修改),则(here line number 36 means seekKey($value, $needle); )
会将此转换为应用程序的200响应(使其看起来像您获取了资源的新副本,即使它仍然是从缓存提供的)。
答案 1 :(得分:1)
这可以通过简单的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