Работа с кешем браузера в одностраничных приложениях


27

Я пытаюсь понять, как правильно обрабатывать кэш веб-браузера для одностраничных приложений.

У меня довольно типичный дизайн: несколько файлов HTML, JS и CSS, реализующих SPA, и куча данных JSON, которые используются SPA. Проблемы возникают, когда я хочу отправить обновление: я обновляю статическую часть сайта и код, который генерирует JSON одновременно, но клиентские браузеры часто кэшируют статическую часть, поэтому старый код пытается обработать новые данные и может (в зависимости от внесенных изменений) столкнуться с проблемами. (В частности, IE выглядит более агрессивно, чем Chrome или Firefox, в отношении использования кэшированного JS без повторной проверки.)

Какой лучший способ справиться с этим?

  1. Убедитесь, что мои изменения JSON обратно совместимы, и предположите, что срок действия кэшей браузера истечет в разумные сроки.
  2. Вставьте какой-то номер версии в статический JS и JSON, а затем выполните, window.location.reload(true);если они не совпадают.
  3. Определите подходящую комбинацию заголовков ( must-revalidateили no-cacheчто-то еще; источники различаются в зависимости от того, как это сделать), чтобы гарантировать, что браузеры всегда повторно проверяют все ресурсы при каждой загрузке, даже если это означает несколько дополнительных циклов для загрузки сайта.
  4. Микро-управление моим контролем кэша и заголовками истекает, так что срок действия статического контента истекает, когда я хочу отправить обновление.
  5. Что-то другое?

1
Слышали, что # 3 и # 4 неожиданно перестали работать во встроенных элементах управления веб-браузера, если ваша среда зла ( кашляющая iOS) от коллег. # 1 и # 2 могут быть выбором уровня приложения, но могут (?) Вызывать проблемы с кэшем для других ресурсов или для частичной загрузки ресурсов. Единственная вещь, которую я видел надежно работающей в готовом к работе коде, - это извлечение yoururl.html? <SomeTimeStamp>, поскольку это подделает большинство механизмов кэширования. Бонус: сверните все ваше веб-приложение в файл, чтобы загрузка выполнялась либо атомарно, либо успешно. Недостаток: лучше всего работает по локальной ссылке. Ваш пробег может варьироваться. Удачи!
J Trana

2
+1 к использованию номера версии или метки времени в качестве параметра URL для ресурсов.
9000

Ответы:


14

Вам нужно решение для очистки кэша . Роль очистки кэша:

  1. Переименуйте ресурсы в уникальное имя в зависимости от их содержимого.
  2. Обновите все ссылки на эти ресурсы.

В проекте на основе Grunt обычно используют grunt-rev, чтобы гарантировать, что все файлы, которые должны быть обновлены, имеют уникальные имена в зависимости от их содержимого.

Если вы гарантируете, что ваши файлы JSON получат имена файлов с кэшированием и ссылки на них в вашем Javascript, клиенты всегда будут загружать файлы JSON, которых ожидает Javascript.

Преимущество именования файлов на основе хеш-функции заключается в том, что файлы, которые не изменились, получат те же имена файлов после очистки кэша, поэтому браузеры могут продолжать безопасно использовать кэшированное содержимое, когда оно не изменилось.

Очевидно, что это именно то, что вы хотите автоматизировать как часть рабочей сборки вашего проекта, поэтому вам не нужно отслеживать изменение имен файлов и ссылок вручную.


2
+1 за выделенный курсивом бит «разорения кэша», который открывает дверь, чтобы фактически продуктивно гуглить этот материал.
Зак Кус

@Ted Percival - йоменские рамки делают это, что я использую, но я вижу проблему. когда я выпускаю новую сборку, браузер может кэшировать index.html со ссылками на старые файлы ... и браузер получает ошибку. как мне это исправить? (A.) символьная ссылка на все старые имена файлов на новые (это работает) (B.) добавление заголовка no-cache в index.html (но это всегда соблюдается) (C.) добавление .htaccess для распознавания восстановленного файла и поиск базового (то есть 12345.main.js -> main.js)
время

5

Вы можете использовать if-modified-since + last-modifiedили if-none-match + etagзаголовки вместе с правильным cache-controlзаголовком. (Могут быть ошибки браузера , но вы ничего не можете сделать в последних браузерах.)

Если файлы статичны, то я предлагаю вам использовать if-modified-since, потому что это можно сделать автоматически с хорошо настроенным HTTP-сервером. Он должен отправить обратно 304, если файл не был изменен с момента последней загрузки.

Я не думаю, что ваши № 1 и № 2 будут работать в долгосрочной перспективе. № 3 или № 4 могут работать. № 3 проще, но вы должны научиться решать эту проблему только один раз. Поэтому я бы попробовал №4 на вашем месте, но решение может зависеть от того, какие браузеры используют ваши клиенты ... Например, IE8 имеет проблемы с обновлением ajax-кэша и т. Д.


2

Если вы можете включить Java Servlet Filter в ваш SPA, вот рабочее решение: CorrectBrowserCacheHandlerFilter.java

По сути, когда ваш браузер запрашивает статические файлы, сервер перенаправляет все запросы на один и тот же, но с параметром запроса хеша ( ?v=azErTнапример), который зависит от содержимого целевого статического файла.

При этом браузер никогда не будет кешировать статические файлы, объявленные в вашем index.htmlпримере (потому что всегда будут получать a 302 Moved Temporarily), но будет кешировать только те, которые имеют хеш-версию ( 200за них ответит сервер ). Таким образом, кэш браузера будет эффективно использоваться для тех статических файлов с хэш-версией.

Отказ от ответственности: я автор CorrectBrowserCacheHandlerFilter.java.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.