簡體   English   中英

NSURLCache與NSURLSession一起不尊重:Cache-Control:max-age:86000,private,must-revalidate

[英]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秒。

使用Charles進行驗證

RFC 7234

以下是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM