Iphone AFNetworking:如何知道响应是否使用缓存?304或200

Iphone AFNetworking:如何知道响应是否使用缓存?304或200,iphone,ios,asihttprequest,afnetworking,http-status-code-304,Iphone,Ios,Asihttprequest,Afnetworking,Http Status Code 304,我找不到我的问题的答案,也许我错过了什么 当我请求url时,我需要知道响应是来自缓存还是来自网络 状态代码是304还是200?(但是AFNetworking始终响应200) 对于ASIHTTPRequest,我曾经从ASIHTTPRequest中检查“didUseCachedResponse”,这非常完美。苹果似乎不想让你知道它是否来自缓存 我找到了一种方法,保存与请求关联的修改日期,并在AFNetWorking回答我时比较该日期 没有我想要的那么干净,但很有效…我想我找到了一个解决方案,可以确

我找不到我的问题的答案,也许我错过了什么

当我请求url时,我需要知道响应是来自缓存还是来自网络

状态代码是304还是200?(但是
AFNetworking
始终响应200)


对于
ASIHTTPRequest
,我曾经从
ASIHTTPRequest
中检查“
didUseCachedResponse
”,这非常完美。

苹果似乎不想让你知道它是否来自缓存

我找到了一种方法,保存与请求关联的修改日期,并在AFNetWorking回答我时比较该日期


没有我想要的那么干净,但很有效…

我想我找到了一个解决方案,可以确定响应是从缓存返回的还是没有使用AFNetworking 2.0。我发现每次从服务器返回一个新的响应(状态为200,而不是304),就会调用
cacheResponseBlock
,它是
AFHTTPRequestOperation
的一个属性。如果应该缓存响应,则块应返回
NSCachedURLResponse
;如果不应该缓存响应,则块应返回nil。这就是筛选响应并只缓存其中一些响应的方法。在本例中,我将缓存来自服务器的所有响应。诀窍是,当服务器发送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中应被视为成功的状态代码,它是通过响应序列化完成的,下面是代码

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

AFHTTPResponseSerializer *respSerializer = [AFHTTPResponseSerializer serializer];
NSMutableIndexSet *responseCodes = [NSMutableIndexSet indexSet];
[responseCodes addIndex:200];
[responseCodes addIndex:304];

[operation setResponseSerializer:respSerializer];

使用此代码,AFNetworking将成功地创建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)
        }
    }
}
在AppDelegate中设置URLCache.shared和URLCache

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”键


适用于所有版本的AFNetworking

我知道这不是您想要的,但是如果您特别想要一个缓存或不想要缓存,您应该检查请求的
NSURLRequestCachePolicy
属性。谢谢,CachePolicy在我的代码中似乎设置得很好,因为当我第二次询问同一个url时,响应来自缓存。问题是我不知道如何在代码中检查它。如果响应来自缓存,我不想做一些额外的繁重代码。似乎苹果不想让你知道它是否来自缓存。我找到了一种方法,保存与请求关联的修改日期,并在AFNetWorking回答我时比较该日期。没有我想的那么干净,但很有效…对于
AFNetworking 3.x
,这个问题有更新的答案吗?请查看我的解决方案,它对我很有效,您不需要存储任何额外数据或对任何内容进行子类化,甚至不需要添加类别。我没有测试这个响应,但它看起来像是一个干净的解决方法。感谢您当前使用此应用程序进行大量网络连接。它处于开发阶段,但经过越来越多的测试,我仍然找不到任何问题。它可以正常工作。您必须小心,因为当服务器没有缓存响应头或缓存响应头不正确时,不会调用此块。如果是这样的话,您会一直认为AFNetworking是从缓存加载的,但实际上它是从服务器加载的。在其他一些情况下,此方法将不会被调用–请参阅apple文档::在我更改NSURLCache磁盘和内存大小限制之前,此方法对大请求(在OS X上)不起作用。我不知道确切的要求,但1.6MB的响应永远不会使用默认值调用响应块。对于
AFURLSessionManager
,它是
dataTaskWillCacheResponse
if (response.allHeaderFields["isCachedReponse"] == nil){
      print("not cache")
} else {
      print("cache")
}