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

时间:2012-08-29 14:50:23

标签: iphone ios asihttprequest afnetworking http-status-code-304

我找不到任何问题的答案,可能是我错过了什么......

当我要求提供网址时,我需要知道响应是来自缓存还是来自网络。

状态代码是304还是200? (但AFNetworking总是回复200)

ASIHTTPRequest我曾经didUseCachedResponse查看“ASIHTTPRequest”,这很完美。

4 个答案:

答案 0 :(得分:24)

我想我找到了一个解决方案来确定是否使用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;
}];

此解决方案对我有用,到目前为止我还没有发现任何问题。但是,如果您对我的解决方案有更好的想法或反对意见,请随时发表评论!

答案 1 :(得分:2)

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

我通过保存修改日期与请求相关联找到了一种方法,并且在AFNetWorking回答我时比较了这个日期。

不像我想的那么干净,但有效......

答案 2 :(得分:1)

有一种方法可以指定在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视为成功

答案 3 :(得分:1)

创建您的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共享的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”键

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

适用于所有版本的 AFNetworking