Будет ли предотвращено кэширование файла с заголовком ответа `Cache-Control:Private` в NSURLCache?

Будет ли файл с заголовком ответа Cache-Control:Private быть защищенным от кэширования в NSURLCache? Либо общий кеш (как в setSharedCache а также NSURLCache.sharedCache()) или заказной?

Чтобы расширить, у меня есть UIWebView что мне нужно получить доступ, когда в автономном режиме. Источник этого WebView имеет несколько внешних файлов CSS и JS, связанных с ним. Я могу кэшировать большую часть сайта (CSS и т. Д. Выглядит на месте), однако, похоже, что он не кэширует конкретный файл JavaScript, который предоставляет важную информацию для сайта. Разница, которую я заметил между файлом, который не будет кэшироваться, и остальным, заключается в том, что его Cache-Control установлен в private (остальные являются общедоступными). Тем не менее, из того, что я прочитал, установка элемента управления кэшированием на частный является предотвращением кэширования на прокси. Повлияет ли это на кэширование на iOS?

Настройка кеша

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    let URLCache: NSURLCache = NSURLCache(memoryCapacity: 10 * 1024 * 1024,
                                            diskCapacity: 50 * 1024 * 1024,
                                                diskPath: nil)

    NSURLCache.setSharedURLCache(URLCache)

    println("Disk cache usage: \(NSURLCache.sharedURLCache().currentDiskUsage)")

    // http://stackru.com/questions/21957378/how-to-cache-using-nsurlsession-and-nsurlcache-not-working
    sleep(1)

    return true
}

Использование кеша

func getWebPage(onCompletion: (NSString, NSURL) -> Void) {

    let url = getApplicationSelectorURL()

    let request = NSURLRequest(URL: url, cachePolicy: .ReturnCacheDataElseLoad, timeoutInterval: 10.0)

    let queue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler: { response, data, error in
        println("Web page task completed")

        var cachedResponse: NSCachedURLResponse

        if (error != nil) {
            println("NSURLConnection error: \(error.localizedDescription)")
            if let cachedResponse = NSURLCache.sharedURLCache().cachedResponseForRequest(request) {
                if let htmlString = NSString(data: cachedResponse.data, encoding: NSUTF8StringEncoding) {
                    onCompletion(htmlString, url)
                } else {
                    println("htmlString nil")
                }
            } else {
                println("cacheResponse nil")
            }
        } else {
            cachedResponse = NSCachedURLResponse(response: response, data: data, userInfo: nil, storagePolicy: .Allowed)
            NSURLCache.sharedURLCache().storeCachedResponse(cachedResponse, forRequest: request)
            if let htmlString = NSString(data: data, encoding: NSUTF8StringEncoding) {
                onCompletion(htmlString, url)
            } else {
                println("htmlString nil")
            }
        }
    })
}

Заполнение UIWebView

APICommunicator.sharedInstance.getWebPage({ htmlString, url in

    dispatch_async(dispatch_get_main_queue(),{
        self.webView.loadHTMLString(htmlString, baseURL: url)
    })

})

2 ответа

Решение

Я закончил тем, что создал метод, похожий на NSURLConnectionDelegate метод willCacheResponseи заменяя Cache-Control:private заголовок.

метод willCacheResponse

func willCacheResponse(cachedResponse: NSCachedURLResponse) -> NSCachedURLResponse?
{        
    let response = cachedResponse.response

    let HTTPresponse: NSHTTPURLResponse = response as NSHTTPURLResponse

    let headers: NSDictionary = HTTPresponse.allHeaderFields

    var modifiedHeaders: NSMutableDictionary = headers.mutableCopy() as NSMutableDictionary

    modifiedHeaders["Cache-Control"] = "max-age=604800"

    let modifiedResponse: NSHTTPURLResponse = NSHTTPURLResponse(
            URL: HTTPresponse.URL!,
            statusCode: HTTPresponse.statusCode,
            HTTPVersion: "HTTP/1.1",
            headerFields: modifiedHeaders)!

    let modifiedCachedResponse = NSCachedURLResponse(
            response: modifiedResponse,
            data: cachedResponse.data,
            userInfo: cachedResponse.userInfo,
            storagePolicy: cachedResponse.storagePolicy)

    return modifiedCachedResponse
}

вызывающий метод

if let cachedResponse = self.willCacheResponse(
        NSCachedURLResponse(response: response,
                                data: data,
                            userInfo: nil,
                       storagePolicy: .Allowed)) {

    NSURLCache.sharedURLCache().storeCachedResponse(cachedResponse, forRequest: request)
}

И теперь он отображается правильно, когда в автономном режиме. Какое путешествие

Да, ответы с политикой управления частным кэшем не кэшируются NSURLCache, В RFC № 2616 говорится

private: указывает, что все или часть ответного сообщения предназначены для одного пользователя и НЕ ДОЛЖНЫ кэшироваться общим кешем. Это позволяет исходному серверу утверждать, что указанные части ответа предназначены только для одного пользователя и не являются действительным ответом на запросы других пользователей. Частный (не общий) кеш МОЖЕТ кешировать ответ.

Что ж, NSURLCache использует sharedCache, который вы даже установили в коде, который вы разместили. Я думаю, это объясняет почти все.

Решением является либо изменение поведения сервера, либо переопределение некоторых методов NSURLCache учебный класс. (Вы можете, например, переписать заголовок на стороне клиента, но это должно быть довольно ужасно.)

Другие вопросы по тегам