如何设置NSURLRequest缓存过期?

我正在使用AFNetworking并且需要在一个响应中缓存数据几分钟。 所以我在app delegate中设置了NSUrlCache,然后在我的请求中设置它:

NSMutableURLRequest *request = //obtain request; request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; 

然后如何设置到期日期:如果数据加载时间超过n分钟,请询问服务器响应而不是磁盘响应?

UPD:假设服务器不支持缓存,我需要在代码中管理它。

所以,我找到了解决方案。

想法是使用connection:willCacheResponse:方法。 在缓存响应之前,它将被执行,我们可以更改响应并返回new,或者返回nil,并且不会缓存响应。 当我使用AFNetworking时,有一个很好的方法:

 - (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block; 

添加代码:

  [operation setCacheResponseBlock:^NSCachedURLResponse *(NSURLConnection *connection, NSCachedURLResponse *cachedResponse) { if([connection currentRequest].cachePolicy == NSURLRequestUseProtocolCachePolicy) { cachedResponse = [cachedResponse responseWithExpirationDuration:60]; } return cachedResponse; }]; 

来自类别的responseWithExpirationDuration

 @interface NSCachedURLResponse (Expiration) -(NSCachedURLResponse*)responseWithExpirationDuration:(int)duration; @end @implementation NSCachedURLResponse (Expiration) -(NSCachedURLResponse*)responseWithExpirationDuration:(int)duration { NSCachedURLResponse* cachedResponse = self; NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)[cachedResponse response]; NSDictionary *headers = [httpResponse allHeaderFields]; NSMutableDictionary* newHeaders = [headers mutableCopy]; newHeaders[@"Cache-Control"] = [NSString stringWithFormat:@"max-age=%i", duration]; [newHeaders removeObjectForKey:@"Expires"]; [newHeaders removeObjectForKey:@"s-maxage"]; NSHTTPURLResponse* newResponse = [[NSHTTPURLResponse alloc] initWithURL:httpResponse.URL statusCode:httpResponse.statusCode HTTPVersion:@"HTTP/1.1" headerFields:newHeaders]; cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:newResponse data:[cachedResponse.data mutableCopy] userInfo:newHeaders storagePolicy:cachedResponse.storagePolicy]; return cachedResponse; } @end 

因此,我们根据http / 1.1在http标头中设置过期秒数。为此我们需要设置一个标头:Expires,Cache-Control:s-maxage或max-age然后创建新的缓存响应,因为属性是只读,并返回新对象。

Swift相当于@ HotJard使用URLSession的解决方案

 extension CachedURLResponse { func response(withExpirationDuration duration: Int) -> CachedURLResponse { var cachedResponse = self if let httpResponse = cachedResponse.response as? HTTPURLResponse, var headers = httpResponse.allHeaderFields as? [String : String], let url = httpResponse.url{ headers["Cache-Control"] = "max-age=\(duration)" headers.removeValue(forKey: "Expires") headers.removeValue(forKey: "s-maxage") if let newResponse = HTTPURLResponse(url: url, statusCode: httpResponse.statusCode, httpVersion: "HTTP/1.1", headerFields: headers) { cachedResponse = CachedURLResponse(response: newResponse, data: cachedResponse.data, userInfo: headers, storagePolicy: cachedResponse.storagePolicy) } } return cachedResponse } } 

然后在自定义类中实现URLSessionDataDelegate协议

 func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Void) { if dataTask.currentRequest?.cachePolicy == .useProtocolCachePolicy { let newResponse = proposedResponse.response(withExpirationDuration: 60) completionHandler(newResponse) }else { completionHandler(proposedResponse) } } 

不要忘记创建配置和会话,将自定义类作为委托引用传递,例如

 let session = URLSession( configuration: URLSession.shared.configuration, delegate: *delegateReference*, delegateQueue: URLSession.shared.delegateQueue ) let task = session.dataTask(with: request) task.resume() 

NSURLCache的响应到期是通过HTTP响应中的Cache-Control标头Cache-Control

编辑我看到你已经更新了你的问题。 如果服务器未在响应中提供Cache-Control标头,则不会缓存它。 对该端点的每个请求都将加载端点,而不是返回缓存的响应。