AFNetworking: Как узнать, использует ли ответ кеш или нет? 304 или 200
Я не могу найти ответ на свой вопрос, может быть, я что-то упустил...
Когда я спрашиваю URL, мне нужно знать, приходит ли ответ из кеша или из сети.
Код статуса 304 или 200? (но AFNetworking
всегда отвечаю 200)
С ASIHTTPRequest
Я раньше проверялdidUseCachedResponse
" от ASIHTTPRequest
это было прекрасно.
3 ответа
Я думаю, что нашел решение, чтобы определить, был ли ответ возвращен из кэша или нет с помощью AFNetworking 2.0. Я обнаружил, что каждый раз, когда с сервера возвращается новый ответ (состояние 200, а не 304), cacheResponseBlock
которая является собственностью AFHTTPRequestOperation
называется. Блок должен вернуться NSCachedURLResponse
если ответ должен быть кэширован или ноль, если это не так. Таким образом, вы можете фильтровать ответы и кэшировать только некоторые из них. В этом случае я кеширую все ответы, которые приходят с сервера. Хитрость в том, что когда сервер отправляет 304, а ответ загружается из кеша, этот блок вызываться не будет. Итак, это код, который я использую:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
BOOL __block responseFromCache = YES; // yes by default
void (^requestSuccessBlock)(AFHTTPRequestOperation *operation, id responseObject) = ^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseFromCache) {
// response was returned from cache
NSLog(@"RESPONSE FROM CACHE: %@", responseObject);
}
else {
// response was returned from the server, not from cache
NSLog(@"RESPONSE: %@", responseObject);
}
};
void (^requestFailureBlock)(AFHTTPRequestOperation *operation, NSError *error) = ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"ERROR: %@", error);
};
AFHTTPRequestOperation *operation = [manager GET:@"http://example.com/"
parameters:nil
success:requestSuccessBlock
failure:requestFailureBlock];
[operation setCacheResponseBlock:^NSCachedURLResponse *(NSURLConnection *connection, NSCachedURLResponse *cachedResponse) {
// this will be called whenever server returns status code 200, not 304
responseFromCache = NO;
return cachedResponse;
}];
Это решение работает для меня, и я не нашел никаких проблем до сих пор. Но, если у вас есть лучшая идея или некоторые возражения против моего решения, не стесняйтесь комментировать!
Кажется, что яблоко не хочет, чтобы вы знали, исходит ли оно из кэша или нет.
Я нашел способ, сохранив дату модификации, связанную с запросом, и сравнил эту дату, когда AFNetWorking отвечает мне.
не так чисто, как я намереваюсь, но работает...
Есть способ указать коды состояния, которые должны рассматриваться как успешные в AFNetworking, это делается через сериализацию ответов, вот код
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
AFHTTPResponseSerializer *respSerializer = [AFHTTPResponseSerializer serializer];
NSMutableIndexSet *responseCodes = [NSMutableIndexSet indexSet];
[responseCodes addIndex:200];
[responseCodes addIndex:304];
[operation setResponseSerializer:respSerializer];
С этим кодом AFNetworking будет рассматривать 304 как успех
Создайте свой класс URLCache и переопределите метод storeCachedResponse
class MyURLCache: URLCache {
override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) {
//adding caching header if needed
var headers = response.allHeaderFields
headers.removeValue(forKey: "Cache-Control")
headers["Cache-Control"] = "max-age=\(5 * 60)" //5 min
//the trick
if (headers["isCachedReponse"] == nil){
headers["isCachedReponse"] = "true"
}
if let
headers = headers as? [String: String],
let newHTTPURLResponse = HTTPURLResponse(url: response.url!, statusCode: response.statusCode, httpVersion: "HTTP/1.1", headerFields: headers) {
let newCachedResponse = CachedURLResponse(response: newHTTPURLResponse, data: cachedResponse.data)
super.storeCachedResponse(newCachedResponse, for: request)
}
}
}
Установите URLCache.shared с вашим URLCache в AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
let cache = MyURLCache(memoryCapacity: 1024 * 1024 * 500, diskCapacity: 1024 * 1024 * 500, diskPath: nil)
URLCache.shared = cache
return true
}
}
В ответ обратный вызов проверяет, есть ли заголовки содержимого ответа ключ "newResponse"
if (response.allHeaderFields["isCachedReponse"] == nil){
print("not cache")
} else {
print("cache")
}
Работает для всех версий AFNetworking