NSURLCache almacena en caching respuestas aleatorias que no deben almacenarse en caching

Estoy implementando una aplicación que hace muchas llamadas de networking a un rest-API que también controlamos. Recientemente, decidimos introducir los encabezados de caching en el lado del server para ahorrar time de networking y server. Como no sabemos de antemano por cuánto time los datos serán válidos, no estamos enviando Cache-control: max-age o Expires encabezados, todo lo que hacemos es enviar un encabezado Last-Modified junto con una E-tag , por lo que siempre golpeó el server, pero las respuestas son bastante rápidas la mayoría de las veces con un 304 . Todo parecía funcionar bien al principio, con muchas requestes en caching. Sin embargo, estoy experimentando algunos errores de datos aleatorios en la aplicación debido al almacenamiento en caching.

Por alguna razón, no puedo entender, en algún momento las requestes se almacenan en caching local y se usan como datos "actualizados" sin llegar al server , cuando en realidad no lo están. El problema se mantiene allí hasta que pasa un time. Entonces todo vuelve al server normalmente, exactamente como se comportaría con un encabezado de cache-control , ¡pero sin él !. Entonces, mi pregunta es:


¿Cómo puede NSURLCache junto con NSURLConnection decidir que una request particular no necesita conectarse cuando la request original no llegó con Cache-control: max-age o Expires header? ¿Alguien ha experimentado efectos similares? ¿Y cómo puedo solucionarlo sin eliminar todo el caching?


Algunos más información de background:

  • Estoy usando AFNetworking , pero se basa en NSURLConnection así que no creo que cambie nada
  • El caching utilizado es la instancia pnetworkingeterminada [NSURLCache shanetworkingURLCache]
  • Es una request GET , y cuando verifico los encabezados de la respuesta en caching, esto es lo que obtengo:

    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"; 
  • No puedo pnetworkingecir o reproducir cuando ocurrirá el error, por lo que las soluciones que dependen de eliminar el caching no son una opción.

  • Estoy usando iOS5 +

¿Cómo puede NSURLCache, junto con NSURLConnection, decidir que una request particular no necesita conectarse cuando …

La sección 13.2 de RFC 2616 dice:

Dado que los serveres de origen no siempre proporcionan times de caducidad explícitos, las cachings HTTP típicamente asignan times de caducidad heurísticos, empleando algorithms que utilizan otros valores de encabezado (como la hora de última modificación) para estimar un time de caducidad plausible. La especificación HTTP / 1.1 no proporciona algorithms específicos, pero impone restricciones en el peor de los casos a sus resultados. Dado que los times de expiración heurísticos pueden comprometer la transparencia semántica, deben usarse con cautela, y alentamos a los serveres de origen a proporcionar times de expiración explícitos tanto como sea posible.

Por lo tanto, es posible que el sistema de carga de URL decida que los datos almacenados en caching son "lo suficientemente frescos", aunque no haya proporcionado un time de vida específico para los datos.

Para get mejores resultados, debe intentar proporcionar una vida específica en sus encabezados de respuesta. Si agregar dicho encabezado es imposible, tal vez podría cambiar la request en su lugar. if-modified-since o cache-control podría ayudarlo a evitar los datos almacenados en caching.

De acuerdo con la statement " en algún momento las requestes se almacenan en caching local y se usan como datos" actualizados "sin llegar al server " Estoy bastante seguro de que sus requestes están en memory caching.

NSURLCache almacena en caching los datos en la memory. no en el disco Entonces déjame explicarte lo que podría estar sucediendo contigo.

Inicia la aplicación. Hace una llamada a un service web, obtiene los datos del server, otra vez hace una llamada y obtiene la respuesta de la memory sin hacer una llamada al server y muestra el resultado.

Dejará la aplicación por un time o reiniciará la aplicación. Comtesting si los datos están en la memory. Si no está disponible, vuelve a hacer una llamada al server y repite el mismo comportamiento.

Recomendaría que escribas tu propio almacenamiento en caching de disco para el mismo en lugar de confiar en NSURLConnection y NSUrlCache. porque algunas de las políticas de almacenamiento en caching todavía no se implementan desde Apple.

asegúrese de que su política de caching NSURLRequest esté configurada en NSURLRequestReturnCacheDataElseLoad

aquí, si está utilizando AFNetworking en AFHTTPClient.m, puede anular el método

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

reemplace la línea 470 con esto

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

lo que está haciendo es decirle a la request que cargue el caching si el server no se actualiza … si el server se actualiza, ignorará el caching y downloadá el contenido del server

FYI: NSURLCache almacena los datos en la memory … si desea almacenar los datos en el disco, puede usar mi class aquí

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