AFNetworking : How to know if response is using cache or not ? 304 or 200

前端 未结 4 1225
栀梦
栀梦 2020-12-05 07:56

I can\'t find any answer to my question, may be I miss something...

When I ask for a url, I need to know if the response comes from the cache or from the net.

<
相关标签:
4条回答
  • 2020-12-05 08:19

    I think I found a solution to determine if response was returned from cache or not using AFNetworking 2.0. I found out that each time a new response is returned from the server (status 200, not 304) the cacheResponseBlock which is a property of AFHTTPRequestOperation is called. The block should return NSCachedURLResponse if response should be cached or nil if it shouldn't. That's way you can filter responses and cache only some of them. In this case, I am caching all responses that comes from the server. The trick is, that when server sends 304 and response is loaded from cache, this block won't be called. So, this is the code I am using:

    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;
    }];
    

    This solution works for me and I haven't found any issues so far. But, if you have a better idea or some objections against my solution, feel free to comment!

    0 讨论(0)
  • 2020-12-05 08:28

    seems that apple doesn't want you to know if it comes from cache or not.

    I found a way by saving modification-date associate with the request, and I compare this date when AFNetWorking answers to me.

    not as clean as I intend, but works...

    0 讨论(0)
  • 2020-12-05 08:36

    Create your URLCache class and override storeCachedResponse method

    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)
            }
        }
    }
    

    Set URLCache.shared with your URLCache in 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
        }
    }
    

    In response callback check if headers of response contents "newResponse" key

    if (response.allHeaderFields["isCachedReponse"] == nil){
          print("not cache")
    } else {
          print("cache")
    }
    

    Works for all version of AFNetworking

    0 讨论(0)
  • 2020-12-05 08:37

    There is a way to specify the status codes that should be treated as success in AFNetworking, it is done through response serialization, here is the code

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    
    AFHTTPResponseSerializer *respSerializer = [AFHTTPResponseSerializer serializer];
    NSMutableIndexSet *responseCodes = [NSMutableIndexSet indexSet];
    [responseCodes addIndex:200];
    [responseCodes addIndex:304];
    
    [operation setResponseSerializer:respSerializer];
    

    With this code AFNetworking will treat 304 as success

    0 讨论(0)
提交回复
热议问题