Подтвердить что ты не робот

AFNetworking: Как узнать, использует ли ответ кеш или нет? 304 или 200

Я не могу найти ответ на свой вопрос, может быть, я что-то пропустил...

Когда я запрашиваю URL-адрес, мне нужно знать, поступает ли ответ из кеша или из сети.

Является ли код состояния 304 или 200? (но AFNetworking всегда отвечает 200)

С ASIHTTPRequest я использовал для проверки "didUseCachedResponse" из ASIHTTPRequest, это было идеально.

4b9b3361

Ответ 1

Я думаю, я нашел решение, чтобы определить, был ли ответ возвращен из кеша или нет, используя 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;
}];

Это решение работает для меня, и до сих пор я не нашел никаких проблем. Но, если у вас есть лучшая идея или какие-то возражения против моего решения, не стесняйтесь комментировать!

Ответ 2

похоже, что яблоко не хочет, чтобы вы знали, исходит ли оно из кеша или нет.

Я нашел способ, сохранив ассоциированную с датой обновления дату, и я сравниваю эту дату, когда AFNetWorking отвечает мне.

не так чист, как я предполагаю, но работает...

Ответ 3

Существует способ указать коды состояния, которые должны быть обработаны как успешные в 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 как успех

Ответ 4

Создайте свой класс 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