![](/img/trans.png)
[英]Alamofire/NSURLSession caching with private Cache-Control and max-age
[英]NSURLCache, together with NSURLSession, does not respect: Cache-Control: max-age:86000, private, must-revalidate
在AppDelegate.m中,我配置了:
NSURLCache *sharedURLCache = [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024 diskCapacity:100 * 1024 * 1024 diskPath:@"FhtHttpCacheDir"];
然后是http請求:
- (void) testRestfulAPI{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://192.168.0.223:8000/v1/topictypes"]];
[request setHTTPMethod:@"GET"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
NSError *error = nil;
if (!error) {
NSURLSessionDataTask *downloadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
NSLog(@"JSON: %@", json);
}
}
}];
[downloadTask resume];
}
}
它第一次請求時,它獲得了帶有Etag + Cache-Control標頭的HTTP 200。 沒問題。
如果我沒有錯, Cache-Control: must-revalidate, max-age=86400, private
將告訴NSURLCache在24小時內將緩存視為新鮮,並且在接下來的24小時內不會進行任何網絡呼叫。
但事實並非如此,第二次發出http請求時,它實際上發出了If-None-Match
標頭並返回HTTP 304。
在我看來,NSURLCache部分工作。 它可以緩存響應,但它不遵循RFC 2616語義,因為Apple doc 在此描述。 僅供參考,我沒有更改緩存策略,因此它使用默認的NSURLRequestUseProtocolCachePolicy
。
我用Google搜索了一天以上的類似問題和其他經驗豐富的類似問題,但我沒有找到任何解決方案。 一些人在AFNetworking的github問題上詢問了同樣的問題,但是作者關閉了這個問題,因為它與AFNetworking 在這里和這里沒有直接關系。
各種相關的stackoverflow帖子也沒有幫助我。
問題是使用Cache-Control響應指令必須重新驗證。
通過省略must-revalidate,就我的理解而言,你已經對你的用例有了完美的定義:
Cache-Control: max-age=86400, private
這可以控制所請求資源被視為新鮮的時間。 經過這段時間后,答案不應再直接來自緩存,而應聯系服務器以驗證后續請求。 在您的情況下,由於服務器提供ETag,iOS會向服務器發送帶有If-None-Match標頭的請求。
為了檢查這一點,我使用了沒有NSURLCache設置的testRestfulAPI方法,並在服務器端配置了最長60秒的時間,因此我不必等待一天來檢查結果。
之后,我每秒觸發一次testRestfulAPI。 我總是從緩存中得到所需的結果。 Charles顯示數據必須來自緩存,因為服務器沒有聯系60秒。
以下是RFC 7234(廢棄RFC 2616)的引用,見5.2.2.1。 它指出:
必須重新驗證指令對於支持某些協議功能的可靠操作是必需的。 在所有情況下,緩存必須遵守必須重新驗證的指令; 特別是,如果緩存因任何原因無法到達原始服務器,它必須生成504(網關超時)響應。
當且僅當無法驗證對表示的請求可能導致不正確的操作(例如無聲的未執行的金融交易)時,服務器才應使用必須重新驗證的指令。
閱讀完之后,如果您將自己置於緩存開發人員的視野中,您可以想象當看到必須重新驗證時,始終會聯系原始服務器,並且只會忽略任何其他指令(如max-age)。 在我看來,緩存通常在實踐中顯示出這種行為。
第5.2.2.1章還有另一節。 我不會隱瞞,其內容如下:
“must-revalidate”響應指令表明,一旦它變得陳舊,高速緩存不得使用響應來滿足后續請求,而無需在源服務器上成功驗證。
這通常被解釋為通過指定max-age和must-revalidate,您可以確定內容何時過時(在max-age seconds之后),然后它必須在源服務器上驗證才能提供內容。
然而,在實踐中,由於上面給出的原因,似乎必須重新驗證總是導致對源服務器上的每個請求的驗證。
嘗試更改這些行
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
對此:
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.urlCache = sharedURLCache; // make sure sharedURLCache is accessible from here
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.