[英]How to use NSURLCache to cache content served by an NSURLProtocol
我写了一个NSURLProtocol
,将检查出站http
请求针对plist
URL的本地路径映射和服务于当地的内容,而不是,然后使用缓存它NSURLCache:
- (void)startLoading
{
//Could this be why my responses never come out of the cache?
NSURLResponse *response =[[NSURLResponse alloc]initWithURL:self.request.URL
MIMEType:nil expectedContentLength:-1
textEncodingName:nil];
//Get the locally stored data for this request
NSData* data = [[ELALocalPathSubstitutionService singleton] getLocallyStoredDataForRequest:self.request];
//Tell the connection to cache the response
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
//Have the connection load the data we just fetched
[[self client] URLProtocol:self didLoadData:data];
//Tell the connection to finish up
[[self client] URLProtocolDidFinishLoading:self];
}
我限制了可以提取本地数据的次数。 目的是,它第一次获取时将来自NSBundle
,但是此后它将使用库存的NSURLCache
来检查它是否应来自缓存或网络 :
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
//Check if we have pre-loaded data for that request
ELAPathSubstitution* pathSub = [[ELALocalPathSubstitutionService singleton] pathSubForRequest:request];
//We don't have a mapping for this URL
if (!pathSub)
return NO;
//If it's been fetched too many times, don't handle it
if ([pathSub.timesLocalDataFetched intValue] > 0)
{
//Record that we refused it.
[pathSub addHistoryItem:ELAPathSubstitutionHistoryRefusedByProtocol];
return NO;
}
//Record that we handled it.
[pathSub addHistoryItem:ELAPathSubstitutionHistoryHandledByProtocol];
return YES;
}
可悲的是,似乎本地数据将进入缓存,但永远不会返回。 这是一个日志片段:
History of [https://example.com/image.png]:
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryHandledByProtocol]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryHandledByProtocol]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryHandledByProtocol]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryCacheMiss]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryDataFetched]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryAddedToCache]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryRefusedByProtocol]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryRefusedByProtocol]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryCacheMiss]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryAddedToCache]
[2014-04-29 18:02:50 +0000] = [ELAPathSubstitutionHistoryRefusedByProtocol]
[2014-04-29 18:02:50 +0000] = [ELAPathSubstitutionHistoryCacheHit]
我的期望是,协议第一次拒绝它后,将导致几次缓存命中,但始终会将其视为未命中,从服务器中获取内容,然后开始获取缓存命中。
我担心的是,我的NSURLProtocol
子类以允许对其进行缓存的方式构造其响应,但是阻止了将它们从缓存中取出。 有任何想法吗?
提前致谢。 :)
与URL加载系统的缓存进行交互是NSURLProtocolClient
对象的职责,该对象充当NSURLProtocol
的客户端。 如果请求使用NSURLRequestUseProtocolCachePolicy
作为缓存策略, NSURLRequestUseProtocolCachePolicy
协议实现来应用正确的协议特定规则来确定是否应缓存响应。
协议实现在适合该协议的任何时候都在其客户端上调用URLProtocol:cachedResponseIsValid:
表明缓存的响应是有效的。 然后,客户端应与URL加载系统的缓存层进行交互。
但是,由于系统提供给我们的客户是私有且不透明的,因此您可能需要自己处理问题并与协议中的系统缓存进行交互。 如果要采用该路径,可以直接使用NSURLCache。 第一步是在协议中覆盖-cachedResponse
。 如果您仔细阅读文档,则默认实现仅根据传递给初始化程序的值进行设置。 覆盖它,以便它访问共享URL缓存 (或您自己的私有URL缓存):
- (NSCachedURLResponse *) cachedResponse {
return [[NSURLCache sharedURLCache] cachedResponseForRequest:[self request]];
}
现在,在通常在客户端上调用cachedResponseIsValid:
的位置,还将NSCachedURLResponse
存储到NSURLCache
。 例如,当您具有一组完整的字节和一个响应时:
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:[self request]];
感谢您提供的信息,但是像Scott一样,我仍然看到缓存问题,并且不清楚具体的责任在哪里。
我确定我的自定义NSURLProtocol的响应已被缓存。 我这样通知协议客户端[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
之后,我可以手动查询NSURLCache,并返回适当的NSCachedURLResponse。
在后续请求中,缓存中有一个我不清楚的请求。 我会假设对于先前提供了etag的请求,NSURLProtocol客户端会在进入我的协议的请求上设置if-none-match标头吗?
我是否真的必须在自定义协议中实现HTTP缓存的那一部分?
我已经通过使用自定义NSUrlCache解决了此问题。 我认为它比NSUrlProtocol更容易使用。 我已经在appstore中存在的app中使用了代码。 用于此目的的代码发布在github上的https://github.com/evermeer/EVURLCache
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.