NSURLRequestCachePolicy.UserProtocolCachPolicy 要求
NSURLRequestCachePolicy.UserProtocolCachPolicy requirements
我正在使用以下代码进行缓存,从服务器收到的响应具有以下 headers。是否需要从请求端设置任何 header,以便缓存工作 10 秒。
Connection Received Resopnse Headers= [Date: Sat, 12 Sep 2015 22:51:16
GMT, Transfer-Encoding: Identity, Server: Apache-Coyote/1.1,
Content-Type: application/json;charset=UTF-8, Expires: Sat, 12 Sep
2015 22:51:26 GMT, Cache-Control: max-age=10, must-revalidate]
没有缓存的强大代码。
import UIKit
class HTTPJSONDonwload: NSObject , NSURLConnectionDataDelegate , NSURLConnectionDelegate {
static let httpjsonDownloader:HTTPJSONDonwload = HTTPJSONDonwload()
func startDownload(){
let serverRequest = getServerURL()
NSURLConnection(request: serverRequest, delegate: self, startImmediately: true)
}
func getServerURL() -> NSMutableURLRequest{
let request:NSMutableURLRequest = NSMutableURLRequest(URL:NSURL(string:"http://citiesfav-jcitiesj.rhcloud.com/Cache/getAllCities")! )
request.cachePolicy = NSURLRequestCachePolicy.UseProtocolCachePolicy
request.HTTPMethod = "POST"
return request
}
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
print("Connection Data= \(NSString(data: data, encoding: NSUTF8StringEncoding))")
}
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
print("Connection Received Resopnse Headers= \((response as! NSHTTPURLResponse).allHeaderFields)")
}
func connection(connection: NSURLConnection, willCacheResponse cachedResponse: NSCachedURLResponse) -> NSCachedURLResponse? {
print("Connection will cache Response")
return cachedResponse
}
}
从 header 中删除 must-revalidate 后,它仍在获取请求。
Connection Received Resopnse Headers= [Cache-Control: max-age=10,
Transfer-Encoding: Identity, Date: Sun, 13 Sep 2015 18:35:43 GMT,
Content-Type: application/json;charset=UTF-8, Server:
Apache-Coyote/1.1, Expires: Sun, 13 Sep 2015 18:35:53 GMT]
后来的调查结果显示 POST 请求确实被缓存了,但不像 GET 那样工作,其中考虑了 max-age。
func startDownload(){
let serverRequest = getServerURL()
let cache = NSURLCache.sharedURLCache()
let response = cache.cachedResponseForRequest(serverRequest)
if response != nil {
serverRequest.cachePolicy = NSURLRequestCachePolicy.ReturnCacheDataDontLoad
}
NSURLConnection(request: serverRequest, delegate: self, startImmediately: true)
}
tl;博士
您需要使用 GET
而不是 POST
。
冗长的解释
问题是您的请求是 POST
。
func getServerURL() -> NSMutableURLRequest{
...
request.HTTPMethod = "POST"
...
}
通常,POST
请求用于在服务器上创建(或有时还用于更新)资源。为创建或更新请求重用缓存的响应没有多大意义,因为无论如何您都必须将请求发送到服务器(否则不会创建或更新任何内容)。似乎 iOS 自动绕过 POST
请求的缓存。
但是,在您的特定情况下,您实际上并不需要 POST
,因为您只是从服务器读取数据。这意味着您应该改用 GET
请求。
func getServerURL() -> NSMutableURLRequest{
...
request.HTTPMethod = "GET"
...
}
我通过以下片段验证了 iOS 系统实际上重用了缓存。
let d = HTTPJSONDonwload()
// Initial request. Can not reuse cache.
d.startDownload()
// Subsequent request after 5 seconds. Should be able to reuse the cache.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(5 * NSEC_PER_SEC)), dispatch_get_main_queue()) {
d.startDownload()
}
// Subsequent request after 11 seconds. Cannot reuse the cache because
// the expiration timeout is 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)), dispatch_get_main_queue()) {
d.startDownload()
}
当我在模拟器中 运行 使用 Charles Proxy 监控网络调用时,我确实只看到两个事件:
第一次调用是初始请求
第二次调用是延迟 11 秒后发出的第三个请求。
请注意,5 秒后发出的第二个请求没有出现,这意味着响应是从缓存中检索的。但是,NSURLConnection
的委托方法仍将被调用,就像响应来自网络一样。因此,通过代码中的日志输出,您将在控制台上看到所有三个请求。
Connection Received Resopnse Headers= [Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Keep-Alive: timeout=15, max=100, Proxy-Connection: Keep-alive, Date: Mon, 14 Sep 2015 06:28:05 GMT, Content-Encoding: gzip, Content-Length: 36, Cache-Control: max-age=10, Vary: Accept-Encoding]
Connection Data= Optional({"1":"New York"})
Connection will cache Response
Connection Received Resopnse Headers= [Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Keep-Alive: timeout=15, max=100, Proxy-Connection: Keep-alive, Date: Mon, 14 Sep 2015 06:28:05 GMT, Content-Encoding: gzip, Content-Length: 36, Cache-Control: max-age=10, Vary: Accept-Encoding]
Connection Data= Optional({"1":"New York"})
Connection Received Resopnse Headers= [Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Keep-Alive: timeout=15, max=99, Proxy-Connection: Keep-alive, Date: Mon, 14 Sep 2015 06:28:16 GMT, Content-Encoding: gzip, Content-Length: 36, Cache-Control: max-age=10, Vary: Accept-Encoding]
Connection Data= Optional({"1":"New York"})
Connection will cache Response
请注意,在第二次请求之后没有 Connection will cache Response
,因为响应是从缓存中检索的,再次缓存它没有意义。
我正在使用以下代码进行缓存,从服务器收到的响应具有以下 headers。是否需要从请求端设置任何 header,以便缓存工作 10 秒。
Connection Received Resopnse Headers= [Date: Sat, 12 Sep 2015 22:51:16 GMT, Transfer-Encoding: Identity, Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Expires: Sat, 12 Sep 2015 22:51:26 GMT, Cache-Control: max-age=10, must-revalidate]
没有缓存的强大代码。
import UIKit
class HTTPJSONDonwload: NSObject , NSURLConnectionDataDelegate , NSURLConnectionDelegate {
static let httpjsonDownloader:HTTPJSONDonwload = HTTPJSONDonwload()
func startDownload(){
let serverRequest = getServerURL()
NSURLConnection(request: serverRequest, delegate: self, startImmediately: true)
}
func getServerURL() -> NSMutableURLRequest{
let request:NSMutableURLRequest = NSMutableURLRequest(URL:NSURL(string:"http://citiesfav-jcitiesj.rhcloud.com/Cache/getAllCities")! )
request.cachePolicy = NSURLRequestCachePolicy.UseProtocolCachePolicy
request.HTTPMethod = "POST"
return request
}
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
print("Connection Data= \(NSString(data: data, encoding: NSUTF8StringEncoding))")
}
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
print("Connection Received Resopnse Headers= \((response as! NSHTTPURLResponse).allHeaderFields)")
}
func connection(connection: NSURLConnection, willCacheResponse cachedResponse: NSCachedURLResponse) -> NSCachedURLResponse? {
print("Connection will cache Response")
return cachedResponse
}
}
从 header 中删除 must-revalidate 后,它仍在获取请求。
Connection Received Resopnse Headers= [Cache-Control: max-age=10, Transfer-Encoding: Identity, Date: Sun, 13 Sep 2015 18:35:43 GMT, Content-Type: application/json;charset=UTF-8, Server: Apache-Coyote/1.1, Expires: Sun, 13 Sep 2015 18:35:53 GMT]
后来的调查结果显示 POST 请求确实被缓存了,但不像 GET 那样工作,其中考虑了 max-age。
func startDownload(){
let serverRequest = getServerURL()
let cache = NSURLCache.sharedURLCache()
let response = cache.cachedResponseForRequest(serverRequest)
if response != nil {
serverRequest.cachePolicy = NSURLRequestCachePolicy.ReturnCacheDataDontLoad
}
NSURLConnection(request: serverRequest, delegate: self, startImmediately: true)
}
tl;博士
您需要使用 GET
而不是 POST
。
冗长的解释
问题是您的请求是 POST
。
func getServerURL() -> NSMutableURLRequest{
...
request.HTTPMethod = "POST"
...
}
通常,POST
请求用于在服务器上创建(或有时还用于更新)资源。为创建或更新请求重用缓存的响应没有多大意义,因为无论如何您都必须将请求发送到服务器(否则不会创建或更新任何内容)。似乎 iOS 自动绕过 POST
请求的缓存。
但是,在您的特定情况下,您实际上并不需要 POST
,因为您只是从服务器读取数据。这意味着您应该改用 GET
请求。
func getServerURL() -> NSMutableURLRequest{
...
request.HTTPMethod = "GET"
...
}
我通过以下片段验证了 iOS 系统实际上重用了缓存。
let d = HTTPJSONDonwload()
// Initial request. Can not reuse cache.
d.startDownload()
// Subsequent request after 5 seconds. Should be able to reuse the cache.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(5 * NSEC_PER_SEC)), dispatch_get_main_queue()) {
d.startDownload()
}
// Subsequent request after 11 seconds. Cannot reuse the cache because
// the expiration timeout is 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)), dispatch_get_main_queue()) {
d.startDownload()
}
当我在模拟器中 运行 使用 Charles Proxy 监控网络调用时,我确实只看到两个事件:
第一次调用是初始请求
第二次调用是延迟 11 秒后发出的第三个请求。
请注意,5 秒后发出的第二个请求没有出现,这意味着响应是从缓存中检索的。但是,NSURLConnection
的委托方法仍将被调用,就像响应来自网络一样。因此,通过代码中的日志输出,您将在控制台上看到所有三个请求。
Connection Received Resopnse Headers= [Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Keep-Alive: timeout=15, max=100, Proxy-Connection: Keep-alive, Date: Mon, 14 Sep 2015 06:28:05 GMT, Content-Encoding: gzip, Content-Length: 36, Cache-Control: max-age=10, Vary: Accept-Encoding]
Connection Data= Optional({"1":"New York"})
Connection will cache Response
Connection Received Resopnse Headers= [Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Keep-Alive: timeout=15, max=100, Proxy-Connection: Keep-alive, Date: Mon, 14 Sep 2015 06:28:05 GMT, Content-Encoding: gzip, Content-Length: 36, Cache-Control: max-age=10, Vary: Accept-Encoding]
Connection Data= Optional({"1":"New York"})
Connection Received Resopnse Headers= [Server: Apache-Coyote/1.1, Content-Type: application/json;charset=UTF-8, Keep-Alive: timeout=15, max=99, Proxy-Connection: Keep-alive, Date: Mon, 14 Sep 2015 06:28:16 GMT, Content-Encoding: gzip, Content-Length: 36, Cache-Control: max-age=10, Vary: Accept-Encoding]
Connection Data= Optional({"1":"New York"})
Connection will cache Response
请注意,在第二次请求之后没有 Connection will cache Response
,因为响应是从缓存中检索的,再次缓存它没有意义。