簡體   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