2015-03-18 18 views
9

Ho trovato un problema con (possibilmente) NSURLCache oggi durante l'ispezione delle intestazioni di richiesta e risposta in Charles Proxy. La questione è un po 'perplessi, ma sono in grado di repro in modo coerente:NSURLCache non funziona quando il valore dell'intestazione di risposta per la codifica del trasferimento è chunk

In poche parole, la questione ha a che fare con il caching di NSURLRequest s utilizzando iOS nativa NSURLCache con il criterio predefinito. Si scopre che la richiesta non viene memorizzata nella cache ogni volta che la risposta ha l'intestazione transfer-encoding: chunked. Ma se l'intestazione della risposta è content-length: xxx, la memorizzazione nella cache funziona correttamente. In particolare, sembra che quando la risposta è suddivisa in blocchi, NSURLCache non salva l'eTag e trascura anche l'accodamento dell'intestazione if-none-match alle richieste successive allo stesso url e, di conseguenza, la memorizzazione nella cache non riesce (come dovrebbe), ovvero viene restituito un 200 di un 304.

Sto testando il simulatore iOS8.2. Anche se non hai una soluzione, mi piacerebbe sapere se hai riscontrato lo stesso problema. Ho trovato almeno one similar report), ed ecco uno related thread posted by my back-end engineer.

+0

Ciao, qualsiasi aggiornamento su questo? –

+0

Nessuno, a parte il fatto che siamo in grado di riprodurre questo bug con alta certezza. Per ora, stiamo cercando di inviare sempre il JSON indietro con l'intestazione di lunghezza del contenuto. Qual è la natura del tuo problema? – rainypixels

+0

Salve, il nostro sistema di backend non può restituire la lunghezza del contenuto perché la risposta è enorme e deve essere restituita come blocchi. Quindi abbiamo bisogno di trovare il modo di mettere in cache una risposta chunked o una documentazione ufficiale che dice che è impossibile. Apprezzo qualsiasi consiglio. –

risposta

0

Dovrebbe funzionare se si aggiungono manualmente i dati di risposta alla cache. Ho una classe di caricamento delle immagini in cui voglio essere sicuro che tutto sia memorizzato nella cache, quindi faccio qualcosa del genere:

- (void)getImageWithURL:(NSURL *)url onCompletion:(void (^)(UIImage *image, NSError *error))completion { 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

    UIImage *cachedImage = [self cachedImageForURLRequest:request]; 
    if (cachedImage) { 
     NSLog(@"Got image from cache."); 
     completion(cachedImage, nil); 
     return; 
    } 

    [[[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     // Manually cache the response. 
     NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data userInfo:nil storagePolicy:NSURLCacheStorageAllowed]; 
     [[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:request]; 
     NSLog(@"Got a fresh image."); 
     completion([UIImage imageWithData:data], error); 
    }] resume]; 
} 

- (UIImage *)cachedImageForURLRequest:(NSURLRequest *)urlRequest { 
    NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:urlRequest]; 
    return [UIImage imageWithData:cachedResponse.data]; 
}