11

Кэширует ли Safari на iOS 6 результаты $.ajax?

15

С момента обновления до iOS 6 мы столкнулись с проблемой, связанной с кэшированием вызовов $.ajax в веб-просмотре Safari. Это происходит в контексте приложения PhoneGap, которое использует веб-просмотр Safari. Наши вызовы $.ajax представляют собой методы POST, и мы установили параметр кэширования в значение false ({cache:false}), однако кэширование все равно происходит. Мы пытались вручную добавить временную метку (TimeStamp) в заголовки, но это не решило проблему.

Дальнейшие исследования показали, что Safari возвращает кэшированные результаты только для веб-сервисов с статической сигнатурой функций, которая не изменяется от вызова к вызову. Например, представьте, что есть функция с названием:

getNewRecordID(intRecordType)

Эта функция получает одинаковые параметры ввода снова и снова, но данные, которые она возвращает, должны быть разными каждый раз.

Похоже, что в стремлении Apple сделать iOS 6 более производительным, они слишком увлеклись настройками кэширования. Кто-нибудь еще сталкивался с таким поведением на iOS 6? Если да, то что именно вызывает эту проблему?

Рабочим решением, которое мы нашли, стало изменение сигнатуры функции на следующую:

getNewRecordID(intRecordType, strTimestamp)

При этом мы всегда передаем параметр TimeStamp и просто игнорируем его на стороне сервера. Это обходит проблему.

5 ответ(ов)

4

После небольшого исследования оказалось, что Safari в iOS 6 будет кэшировать POST-запросы, если они не имеют заголовков Cache-Control или даже если в заголовках указан "Cache-Control: max-age=0".

Единственный способ, который я нашел, чтобы предотвратить это кэширование на глобальном уровне, а не приклеплять случайные параметры к URL сервисных вызовов, — это установить заголовок "Cache-Control: no-cache".

Итак:

  • Нет заголовков Cache-Control или Expires = Safari в iOS 6 будет кэшировать
  • Cache-Control max-age=0 и немедленный Expires = Safari в iOS 6 будет кэшировать
  • Cache-Control: no-cache = Safari в iOS 6 НЕ будет кэшировать

Я подозреваю, что Apple использует положение из спецификации HTTP в разделе 9.5 о POST:

Ответы на этот метод не кэшируемы, за исключением случаев, когда ответ включает соответствующие заголовки Cache-Control или Expires. Тем не менее, ответ 303 (See Other) может быть использован, чтобы направить пользовательский агент на извлечение кэшируемого ресурса.

Таким образом, теоретически возможно кэшировать ответы на POST… кто бы мог подумать. Но ни один другой разработчик браузеров не считал бы это хорошей идеей до сих пор. Однако это не учитывает кэширование, когда заголовки Cache-Control или Expires не установлены, только когда они есть. Поэтому, вероятно, это ошибка.

Ниже приведено, что я использую в нужной части своей конфигурации Apache для настройки кэширования для всего моего API, так как на самом деле я не хочу кэшировать ничего, даже GET-запросы. Я не знаю, как установить это только для POST.

Header set Cache-Control "no-cache"

Обновление: Только что заметил, что не указал, что кэширование происходит только в случае одинаковых POST-запросов, так что если изменить любые данные POST или URL, то все будет в порядке. Поэтому, как упоминалось в других источниках, просто добавьте случайные данные к URL или немного данных POST.

Обновление: Вы можете ограничить "no-cache" только для POST-запросов вот таким образом в Apache:

SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST
1

Надеюсь, это будет полезно другим разработчикам, которые сталкиваются с этой проблемой. Я обнаружил, что следующее предотвращает кэширование POST-ответов в Safari на iOS 6:

  • добавление заголовка [cache-control: no-cache] в запрос
  • добавление переменной параметра URL, например, текущего времени
  • добавление [pragma: no-cache] в заголовки ответа
  • добавление [cache-control: no-cache] в заголовки ответа

Мое решение было следующим в Javascript (все мои AJAX-запросы — POST).

$.ajaxSetup({
    type: 'POST',
    headers: { "cache-control": "no-cache" }
});

Я также добавляю заголовок [pragma: no-cache] во многие свои серверные ответы.

Если вы используете вышеуказанное решение, имейте в виду, что любые вызовы $.ajax(), у которых установлен параметр global: false, НЕ будут использовать настройки, указанные в $.ajaxSetup(), поэтому вам нужно будет снова добавить заголовки.

0

У меня была такая же проблема с веб-приложением, получающим данные из веб-службы ASP.NET.

Вот что сработало для меня:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}

Этот код помогает установить заголовок кэширования ответа, предотвращая его кэширование клиентом. Надеюсь, это поможет и вам!

0

Этот фрагмент кода JavaScript отлично работает с jQuery и jQuery Mobile:

$.ajaxSetup({
    cache: false,
    headers: {
        'Cache-Control': 'no-cache'
    }
});

Просто разместите его в своем JavaScript-коде (после загрузки jQuery, и лучше всего перед выполнением AJAX-запросов), и это должно помочь.

0

Быстрый обходной путь для GWT-RPC сервисов — добавить следующую строку во все удаленные методы:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");

Таким образом, вы отключите кэширование для ответов на эти вызовы. Это может помочь избежать проблем с кешированием, когда клиент получает устаревшие данные.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь