如何知道 NSURLSessionDataTask 响应是否来自缓存?
How to know if NSURLSessionDataTask response came from cache?
我想确定来自 NSURLSessionDataTask
的响应是来自缓存,还是来自服务器
我正在从
创建我的 NSURLSessionDataTask
request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
想到两个简单的选项:
- 在发出请求之前调用
[[NSURLCache sharedURLCache] cachedResponseForRequest:request]
,存储缓存的响应,然后在接收完数据后再次调用,比较两次缓存的响应,看它们是否相同。
- 使用
NSURLRequestReturnCacheDataDontLoad
缓存策略发出初始请求,如果失败,使用更合理的策略发出第二个请求。
第一种方法通常更可取,因为第二种方法将 return 缓存中存在的数据,即使它是陈旧的。但是,在极少数情况下(例如离线模式),这可能就是您想要的,这就是我提到它的原因。
如果您只是出于好奇需要信息,您可以通过 Xcode 运行时网络指标查看您的网络使用情况。将策略更改为不同的设置并观察差异。
如果您想使用缓存,那么在客户端禁用缓存并不是一个好的答案。
如果服务器设置了缓存 headers (etag, cache-control="no-store") 然后 NSURLSession 将重新生效并根据来自的 200 / 304 响应为您提供缓存/新鲜响应服务器。但是,在您的代码中,无论 NSUrlSession 收到 200 还是 304,您将始终看到 statusCode 200。这是限制性的,因为您可能希望在响应未更改时跳过解析、re-creating objects 等。
我所做的解决方法是使用响应中的 etag 值来确定是否发生了某些变化
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
NSString *etag = (httpResp && [httpResp isKindOfClass:[NSHTTPURLResponse class]]) ? httpResp.allHeaderFields[@"Etag"] : nil;
BOOL somethingHasChanged = [etag isEqualToString:oldEtag];
为了知道 URLSessionDataTask 响应是来自缓存还是网络,您必须使用自定义 URLSession 并为其提供 URLSessionTaskDelegate
,它必须实现以下方法:
func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics)
您会在 metrics
中找到非常有用的信息,尤其是请求的事务指标列表。每个事务指标都有一个 属性 resourceFetchType
,可以是 .localCache、.networklLoad、.serverPush 或 .unknown。
这里有更多信息:Apple documentation regarding URLSessionTaskDelegate
我想确定来自 NSURLSessionDataTask
的响应是来自缓存,还是来自服务器
我正在从
创建我的NSURLSessionDataTask
request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
想到两个简单的选项:
- 在发出请求之前调用
[[NSURLCache sharedURLCache] cachedResponseForRequest:request]
,存储缓存的响应,然后在接收完数据后再次调用,比较两次缓存的响应,看它们是否相同。 - 使用
NSURLRequestReturnCacheDataDontLoad
缓存策略发出初始请求,如果失败,使用更合理的策略发出第二个请求。
第一种方法通常更可取,因为第二种方法将 return 缓存中存在的数据,即使它是陈旧的。但是,在极少数情况下(例如离线模式),这可能就是您想要的,这就是我提到它的原因。
如果您只是出于好奇需要信息,您可以通过 Xcode 运行时网络指标查看您的网络使用情况。将策略更改为不同的设置并观察差异。
如果您想使用缓存,那么在客户端禁用缓存并不是一个好的答案。
如果服务器设置了缓存 headers (etag, cache-control="no-store") 然后 NSURLSession 将重新生效并根据来自的 200 / 304 响应为您提供缓存/新鲜响应服务器。但是,在您的代码中,无论 NSUrlSession 收到 200 还是 304,您将始终看到 statusCode 200。这是限制性的,因为您可能希望在响应未更改时跳过解析、re-creating objects 等。
我所做的解决方法是使用响应中的 etag 值来确定是否发生了某些变化
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
NSString *etag = (httpResp && [httpResp isKindOfClass:[NSHTTPURLResponse class]]) ? httpResp.allHeaderFields[@"Etag"] : nil;
BOOL somethingHasChanged = [etag isEqualToString:oldEtag];
为了知道 URLSessionDataTask 响应是来自缓存还是网络,您必须使用自定义 URLSession 并为其提供 URLSessionTaskDelegate
,它必须实现以下方法:
func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics)
您会在 metrics
中找到非常有用的信息,尤其是请求的事务指标列表。每个事务指标都有一个 属性 resourceFetchType
,可以是 .localCache、.networklLoad、.serverPush 或 .unknown。
这里有更多信息:Apple documentation regarding URLSessionTaskDelegate