NSURLCache caches random responses that cannot be cached

I am implementing an application that makes many network calls for rest-api, which we also control. Recently, we decided to introduce caching headers on the server side to save some valuable network and server time. Since we do not know in advance how long the data will be valid, we do not send Cache-control: max-age or Expires headers, all we do is send the Last-Modified header with the E-tag , so we always get to the server but the answers are pretty fast in most cases with 304 . At first, everything seemed to work fine, with many requests being cached. However, I am experiencing some random data errors in the application due to caching.

For some reason, I can’t understand, in some cases, requests are locally cached and used as “updated” data without getting to the server when they really aren’t. The problem persists until some time has passed. Then everything returns to the server again, just as it behaves with the cache-control header, but without it !. So my question is:


How can NSURLCache along with NSURLConnection decide that a particular request does not need to enter the network when the original request did not come with the Cache-control: max-age or Expires headers? Has anyone experienced similar effects? And how can I solve this problem without deleting the entire cache?


Additional Information:

  • I use AFNetworking , but it relies on NSURLConnection , so I don’t think it is changing anything.
  • The cache used is the default [NSURLCache sharedURLCache] instance [NSURLCache sharedURLCache]
  • This is a GET request, and when I check the headers from the cached response, this is what I get:

    po [response allHeaderFields]

     "Access-Control-Allow-Headers" = "Content-Type"; "Access-Control-Allow-Methods" = "GET, POST, DELETE, PUT"; "Access-Control-Allow-Origin" = "*"; Connection = "keep-alive"; "Content-Encoding" = gzip; "Content-Length" = 522; "Content-Type" = "application/json"; Date = "Mon, 02 Sep 2013 08:00:38 GMT"; Etag = "\"044ad6e73ccd45b37adbe1b766e6cd50c\""; "Last-Modified" = "Sat, 31 Aug 2013 10:36:06 GMT"; Server = "nginx/1.2.1"; "Set-Cookie" = "JSESSIONID=893A59B6FEFA51566023C14E3B50EE1E; Path=/rest-api/; HttpOnly"; 
  • I cannot predict or reproduce when an error occurs, so decisions that rely on deleting the cache are not an option.

  • I am using iOS5 +
+7
ios caching nsurlconnection afnetworking nsurlcache
source share
3 answers

How NSURLCache, together with NSURLConnection, decides that a particular request is not required online when ...

Section 13.2 of RFC 2616 says:

Because origin servers do not always provide an explicit expiration time, HTTP caches usually assign a heuristic expiration time using algorithms that use other header values ​​(such as Last-Modified time) to evaluate likelihood. The HTTP / 1.1 specification does not provide specific algorithms, but imposes the worst restrictions on their results. Since heuristic expiration times can jeopardize semantic transparency, they should be used with caution, and we recommend that origin servers provide explicit expiration dates as much as possible.

Thus, it is possible that the URL loading system decides that the cached data is “fresh enough,” even if you did not provide a specific lifetime for the data.

For best results, you should try to indicate a specific lifetime in your response headers. If you cannot add such a title, you may be able to modify the query. if-modified-since or cache-control can help you avoid cached data.

+4
source share

According to the statement, “ at some point, requests are locally cached and used as“ updated ”data without going to the server . I am sure that your requests are cached in memory.

NSURLCache caches data in memory. not on disk. So let me explain what can happen to you.

You are launching the application. It makes a web service call, it retrieves data from the server, you make the call again, and it retrieves the response from memory without calling the server and displays the result.

You leave the application for a while or restart the application. It checks if the data is in memory. If it is unavailable, it again makes a call to the server and repeats the same behavior.

I would recommend you write your own disk caching for the same, instead of relying on NSURLConnection and NSUrlCache. because some caching policies are still not implemented by Apple.

+2
source share

make sure your NSURLRequest cache policy is set to NSURLRequestReturnCacheDataElseLoad

here, if you use AFNetworking in AFHTTPClient.m, you can override the method

 - (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters 

replace line 470 with this

  NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:15]; 

what you are actually doing is to report a request to load the cache if the server is not updated. If the server is updated, it will ignore the cache and download content from the server.

FYI: NSURLCache stores data in memory. If you want to save data to disk, you can use my class here.

https://github.com/shoeb01717/Disc-Cache-iOS

+2
source share

All Articles