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