繁体   English   中英

如何使用NSURLCache缓存NSURLProtocol服务的内容

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM