Iphone AFNetworking:如何知道响应是否使用缓存?304或200
我找不到我的问题的答案,也许我错过了什么 当我请求url时,我需要知道响应是来自缓存还是来自网络 状态代码是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回答我时比较该日期 没有我想要的那么干净,但很有效…我想我找到了一个解决方案,可以确
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")
}