У меня есть одностраничное приложение, и мне нужно, чтобы клиенты были в последней версии. Кэширование является агрессивным, поэтому ждать, пока они станут недействительными, невозможно.
Есть ли способ сказать клиенту посмотреть ресурс (скажем, что-то вроде build.txt), и если этот ресурс содержит номер сборки больше, чем текущий загруженный, аннулировать кеш и обновить?
Просто используя location.reload()
?
В моем случае да, так как мы использовали управление версиями ресурсов CSS/JS/изображений.
@DavidAlsh location.reload()
перезагрузит главную страницу, но не сделает недействительным кеш всех загружаемых ресурсов, таких как файлы CSS и JS.
Я не думаю, что есть хороший способ заставить клиентов автоматически очищать свои кеши. Перед обновлением следует сократить время жизни кэша.
Чтобы сделать это в облачном фронте, мне просто нужно установить собственную длину кэша, верно? Он перезапишет заголовки кеша, поступающие из источника?
Поскольку этот вопрос был помечен progressive-web-apps
, я предполагаю, что он устанавливает сервис-воркер, который агрессивно кэширует ресурсы.
Эта почта работает, но показывает всплывающее окно «доступна новая версия» для PWA — даже если это не то поведение, которое вам нужно, оно многое объясняет в том, как обновляются сервис-воркеры.
Этот вопрос/ответ также указывает, как часто сервис-воркер проверяет наличие обновлений.
Этот вопрос/ответ рассказывает о плюсах и минусах постоянного использования skipWaiting
, чтобы клиент всегда был в курсе последних событий.
Редактировать: Если вы имеете дело только с обычным кэшем HTTP, попробуйте использовать location.reload(true)
(перезагрузить с установленным флагом forcedReload
), когда обнаружите, что на сервере есть более новая версия. В прошлом я делал это, помещая номер выпуска в код js во время сборки/выпуска и заставляя сервер добавлять свой номер выпуска к каждому ответу в качестве заголовка. Простое сравнение значений после вызова ajax может подтвердить, совпадают ли номера выпусков пользовательского интерфейса и сервера, и принять меры, если они не совпадают.
У него есть сервисворкер, я забыл упомянуть выше. На данном этапе сервисворкер имеет только пустой обработчик выборки — будет ли это все же изменять поведение кэширования?
Хм, я бы так не подумал - обычно вам нужен какой-то код, чтобы включить предварительное кэширование, с чем, как я думал, вы будете иметь дело. Если вы имеете дело с обычным http-кэшем, вы можете обойтись Location.reload(true)
— обратите внимание на набор параметров forceReload
. Я немного обновлю свой ответ.
Я написал следующий сервис Angular. По сути, он опрашивает файл build.txt
, который находится в папке /assets
, и проверяет, отличается ли он от сборки в своей собственной среде. gist.github.com/alshdavid/032ea535f222646dc74420e20b28faa1
Спасибо Джоно Джоб за помощь в достижении этого решения.
В итоге я сделал следующее:
В моем конвейере сборки я добавил следующие две строки перед сборкой клиента.
- sed -i -e "s/{{build-number}}/${CI_COMMIT_SHORT_SHA}/g" ./src/environments/environment.prod.ts
- echo $CI_COMMIT_SHORT_SHA > ./src/assets/build.txt
Первая строка помещает хэш фиксации в скомпилированный пакет javascript, вторая создает текстовый файл с хэшем фиксации в качестве содержимого.
Затем я настроил службу Angular, которая использует http-клиент для опроса текстового файла, содержащего хэш фиксации. Он проверяет, отличается ли хэш в текстовом файле от хеша, загруженного из пакета javascript.
Теория здесь заключается в том, что пакет Javascript может быть кэширован, но HTTP-запрос на получение файла build.txt не будет. Позволяя мне проверить разницу между хэшами сборки, хранящимися в двух.
Если служба обнаружит разницу в сборках, она отобразит подсказку пользователю, уведомляющую его об обновлении, которое при нажатии обновит страницу.
Обновление выполняется с помощью window.location.reload(true)
. TypeScript сообщает мне, что параметр устарел, хотя он все еще работает.
Вот суть вышеупомянутого сервиса Angular: https://gist.github.com/alshdavid/032ea535f222646dc74420e20b28faa1
В моем APM я вижу, что в течение нескольких часов после отправки обновления все клиенты были обновлены до последней версии.
Так что наверное работает.
У меня было промежуточное ПО, которое прикрепляло текущий идентификатор фиксации git в качестве заголовка ко всем ответам API. Если он изменился, я сделал полную перезагрузку. Возможно, что-то в этом духе?