Как заставить браузер перезагружать кешированные файлы CSS и JavaScript

Я заметил, что некоторые браузеры (в частности, Firefox и Опера) очень рьяно используют кэшированные копии файлов .css и .js даже между сессиями браузера. Это приводит к проблеме, когда вы обновляете один из этих файлов, но браузер пользователя продолжает использовать кэшированную копию.

Каков наиболее элегантный способ заставить браузер пользователя перезагружать файл после его изменения?

В идеале решение не заставит браузер перезагружать файл при каждом посещении страницы.


Я нашел полезными предложения Джона Милликина и da5id's. Оказывается, для этого есть термин: автоматическое управление версиями.

Я опубликовал новый ответ ниже, который представляет собой комбинацию моего исходного решения и предложения Джона.

Другая идея, предложенная SCdF, - добавить в файл фиктивную строку запроса. (Некоторый код Python для автоматического использования метки времени в качестве ложной строки запроса был представленный число Пи..)

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

У меня есть это в моем .htaccess, и никогда не было проблем с кешированными файлами: ExpiresActive On ExpiresDefault "modification".

Frank Conijn 15.05.2014 18:06

Я определенно согласен с тем, что добавление информации о версиях к URL-адресу файла - безусловно, лучший способ. Это всегда работает для всех. Но, если вы его не используете, и вам просто нужно время от времени перезагружать этот файл CSS или JS в вашем собственном браузере ... просто откройте его на отдельной вкладке и нажмите SHIFT-reload (или CTRL-F5)! Вы можете эффективно сделать то же самое с помощью JS, загрузив файл в (скрытый) iframe, дождавшись его загрузки и затем вызвав iframe.contentWindow.location.reload(true). См. Метод (4) stackoverflow.com/a/22429796/999120 - это касается изображений, но то же самое.

Doin 27.12.2015 08:17

Я очень ценю то, как был задан этот вопрос, и с тех пор он обновляется. Он полностью описал то, чего я должен ожидать в ответах. С этого момента я буду следовать этому подходу в своих вопросах. Ваше здоровье!

rd22 01.08.2016 12:46

Для справки: удаленный ответ da5id - это «Если обновление достаточно большое / важное, я обычно меняю имя файла»..

Peter Mortensen 28.11.2020 06:48

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

WebDevNoob 24.02.2021 13:00
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1 043
5
457 236
55

Ответы 55

Это решение написано на PHP, но его легко адаптировать к другим языкам.

Исходное регулярное выражение .htaccess может вызывать проблемы с такими файлами, как json-1.3.js. Решение состоит в том, чтобы перезаписать только в том случае, если в конце ровно 10 цифр. (Поскольку 10 цифр покрывают все временные метки с 9.09.2001 по 20.11.2266.)

Во-первых, мы используем следующее правило перезаписи в .htaccess:

RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ . [L]

Теперь мы пишем следующую функцию PHP:

/**
 *  Given a file, i.e. /css/base.css, replaces it with a string containing the
 *  file's mtime, i.e. /css/base.1221534296.css.
 *
 *  @param $file  The file to be loaded.  Must be an absolute path (i.e.
 *                starting with slash).
 */
function auto_version($file)
{
  if (strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
    return $file;

  $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
  return preg_replace('{\.([^./]+)$}', ".$mtime.$1", $file);
}

Теперь, где бы вы ни включали свой CSS, измените его следующим образом:

<link rel = "stylesheet" href = "/css/base.css" type = "text/css" />

К этому:

<link rel = "stylesheet" href = "<?php echo auto_version('/css/base.css'); ?>" type = "text/css" />

Таким образом, вам больше не придется изменять тег ссылки, и пользователь всегда будет видеть последнюю версию CSS. Браузер сможет кэшировать файл CSS, но когда вы внесете какие-либо изменения в свой CSS, браузер увидит это как новый URL-адрес, поэтому он не будет использовать кэшированную копию.

Это также может работать с изображениями, значками и JavaScript. В основном все, что не генерируется динамически.

Мой собственный сервер статического содержимого делает то же самое, за исключением того, что я использую параметр для управления версиями (base.css? V = 1221534296), а не изменение имени файла (base.1221534296.css). Я подозреваю, что ваш способ может быть немного более эффективным. Очень круто.

Jens Roland 03.06.2011 00:55

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

Sanghyun Lee 29.07.2011 16:47

@ Кип: Очень хорошее решение. Перезапись URL-адресов, очевидно, может предложить гораздо больше, чем просто красивое оформление URL-адресов.

James P. 06.08.2011 16:51

@Sangdol: То, что вы можете сделать с PHP, - это копия и md5, чтобы проверить, изменился ли файл. Если md5 файла изменился => версия ++.

James P. 06.08.2011 16:52

Примечание: если вы используете Zend Framework, это правило перезаписи должно работать поверх других правил.

understack 24.01.2012 14:51

Это хорошо, но я работаю над системой, в которой некоторые css / js загружаются с другого сервера, поэтому через URL-адрес, а не по абсолютному пути. Это всего лишь мысль, но я думаю, что функция php может быть расширена, чтобы охватить этот случай, путем вызова php get_headers (), получения последней измененной даты, преобразования ее в строку поиска mtime и выполнения preg_replace как есть.

eflat 20.04.2012 04:45

FWIW, я использовал приведенный выше код: auto_version() и rewriteRules во многих небольших файлах JS / CSS (~ 20, в основном 1–100 КБ). Это, по-видимому, сильно загружает мой кеш браузера (Chrome v19), потому что вентилятор на моем Mac (OS X Lion) начинает сходить с ума. Я смог исправить это, отключив кеш в инструментах разработчика. Кто-нибудь знает, почему это происходит?

tim peterson 22.06.2012 16:10

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

Tomáš Fejfar 25.09.2012 03:34

@JensRoland: Мне любопытно узнать ваш комментарий. Мне кажется, что при использовании строк запроса не потребуются дополнительные накладные расходы правила mod_rewrite. Есть ли какой-нибудь конкретный браузер, который не загружает файл повторно с другой строкой запроса, или есть другие причины для вашего подозрения?

Alix Axel 27.11.2012 05:52

@AlixAxel: Нет, браузеры будут повторно загружать его при изменении параметра, но некоторые общедоступные прокси-серверы не кэшируют файлы с параметрами URL-адреса, поэтому рекомендуется включать версию в путь. И накладные расходы mod_rewrite ничтожны по сравнению с любым другим узким местом производительности в WPO.

Jens Roland 27.11.2012 15:54

@JensRoland: Достаточно честно. Я по-прежнему предпочитаю подход со строкой запроса, он проще и имеет меньше зависимостей, о которых нужно беспокоиться.

Alix Axel 27.11.2012 16:17

Никто не хочет изобретать велосипед, есть ли для этого простой API / библиотека? Я имею в виду без полноценного MVC / Rail-подобного фреймворка, и его можно просто вставить и заменить в существующий код.

Dennis C 21.06.2013 12:26

Просто отметим, что мы использовали * .css? V = 2342323423, и он не работал до трех обновлений и очистки кеша.

Michael J. Calkins 08.10.2013 03:39

Я изменил это, чтобы поиграть с "/" лучше. gist.github.com/clouddueling/6877043

Michael J. Calkins 08.10.2013 03:50

@ TomášFejfar, это не будет проблемой, если вы кешируете вывод php в каком-то обратном прокси, таком как Squid или Varnish.

Patrick James McDougle 24.10.2013 06:48

Как это выглядит с NGINX? Если кто-то может ответить на этот вопрос, он также может ответить на этот вопрос: stackoverflow.com/questions/9423138/…

tim peterson 17.12.2013 03:01

@MichaelCalkins У меня была такая же проблема. Не используйте имя переменной со значением. Просто используйте *.css?2342323423. Похоже, это сработало для меня.

Gavin 05.06.2014 02:39

Действительно ли необходима первая проверка file_exists? filemtime вернет false в случае сбоя, так почему бы просто не присвоить значение filemtime переменной и проверить, является ли оно ложным, прежде чем переименовывать файл? Это сократило бы одну ненужную файловую операцию, которая действительно увеличила бы объем.

Gavin 05.06.2014 03:21

Я сократил функцию до этого: $filetime = strpos($file, '/') === 0 ? filemtime($_SERVER['DOCUMENT_ROOT'] . $file) : false; if ($filetime) return preg_replace('{\.([^./]+)$}', ".$filetime).$1", $file); else return $file;

Gavin 05.06.2014 03:36

Я сделал что-то подобное (на основе jsp-тегов), но это не решает проблему одного из этих ресурсов javascript программно, включая .css, изображения, другие javascript или другие ресурсы. Для этого почти требуется, чтобы javascript был переписан во время сборки или ... волшебный метод Google, упомянутый в другом ответе.

ticktock 27.08.2014 03:01

Умное решение! Но использовать его с публичным CDN непросто. Перезапись имени файла также должна выполняться в файлах CDN. В то время как с решением для строки запроса CDN может справиться с этим (опция Amazon Cloudfront: «Перенаправить строки запроса»)

kheraud 23.01.2015 18:13

Отличный пост о проблеме кеширования строки запроса: bizcoder.com/caching-resources-with-query-strings

kheraud 26.01.2015 13:40

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

Dariux 19.03.2015 13:33

@ TomášFejfar - когда это может быть проблемой, что это касается файловой системы? Файловая система все равно сильно затронута - например, база данных. Может ли действительно проверка времени последнего изменения файла быть долгой по сравнению с другими вещами, такими как база данных? И, кстати, я вижу в документах, что результат filemtime кэшируется php.net/manual/en/function.filemtime.php

Dariux 19.03.2015 17:14

Еще одна вещь для тех, кто придет сюда в будущем: в PHP двойная обратная косая черта в регулярном выражении работает, но, похоже, технически некорректна. Смотрите regex101.com/r/eA4zP3/1 против regex101.com/r/eA4zP3/2.

seanvalencourt 05.08.2015 21:19

@arcodesign Регулярное выражение .htaccess изменяет base.1221534296.css на base.css, которое является фактическим именем файла в файловой системе. Регулярное выражение в PHP не имеет двойной обратной косой черты - у нас есть строка PHP, содержащая регулярное выражение. \\ в строке PHP кодирует одну обратную косую черту.

Kip 05.08.2015 21:22

Итак, скажем, вы используете varnish в качестве прокси-сервера для кеширования, нужно ли изменять какой-либо код в ответе? @PatrickJamesMcDougle

John Jackson 07.11.2016 23:05

@JohnJackson нет, если у вас есть подходящий механизм для аннулирования кеша

Patrick James McDougle 10.11.2016 02:52

Каков выигрыш в производительности, если вы сделаете это таким образом, по сравнению с простым добавлением filemtime в качестве запроса к файлу?

doz87 21.12.2016 08:13

@Kip Как изменить номер версии файла. только когда меняется не каждый раз?

iit2011081 28.07.2017 11:04

Спасибо, @Kip. Но я не знаю, как переписать правило в .htaccess в Javascript

Tuan Nguyen 06.04.2018 09:56

Это единственное законное решение. Добавление строк запроса к ссылкам на статический контент - плохая идея, поэтому все Google, GTMetrix и т. д. Поднимают для этого флаги. Изменение имени совершенно элегантно и заставляет браузер обновляться ТОЛЬКО, когда вам это нужно. Строки запроса нарушают кеширование для некоторых браузеров, что НИКОГДА не следует рассматривать как решение (это взлом, а не решение).

Nate I 24.04.2018 21:02

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

Telarian 15.04.2019 23:43

@JarrodW. Я могу определенно согласиться с тем, что иногда вам просто нужно временное решение, мне просто не нравится то, что работает только в определенных браузерах. Браузеру в любом случае необходимо сделать запрос на JS; мы здесь вообще не добавляем запрос. Добавление строки запроса по-прежнему требует, чтобы браузер запрашивал ее с сервера, и весь смысл обхода кеширования заключается в том, чтобы в первую очередь принудительно выполнить этот запрос.

Nate I 16.04.2019 17:40

@Kip нет смысла писать \d внутри символьного класса. Кроме того, вероятно, лучше использовать разделитель шаблонов, который не имеет особого значения в регулярном выражении - это улучшит удобочитаемость человека. Двойная косая черта в php может быть одинарной. Возможно, избегайте группы захвата. На ваше рассмотрение: 3v4l.org/PPbUW

mickmackusa 05.12.2019 10:04

@Kip, вы сказали, что это можно легко адаптировать к JavaScript, но, честно говоря, я вроде как новичок в JS и ничего не знаю о PHP. Как мне адаптировать это к JS? о чем этот файл .htaccess?

S. Naj 03.08.2020 01:28

Что делать, если файлы находятся в хранилище CDN, а не на сервере сайта?

Avishay28 22.08.2020 13:20

может кто-нибудь сказать мне, где я должен написать функцию php. В файле .htaccess или я должен создать новый файл php.

Sravan Kumar 26.08.2020 10:34

Вы можете просто поместить ?foo=1234 в конец импорта CSS / JavaScript, изменив 1234 на все, что вам нравится. Взгляните на исходный HTML-код Stack Overflow для примера.

Идея заключается в том, что параметры ? в любом случае отбрасываются / игнорируются в запросе, и вы можете изменить это число при развертывании новой версии.


Примечание: Есть некоторые аргументы относительно того, как именно это влияет на кеширование. Я считаю, что общая суть заключается в том, что запросы ПОЛУЧАТЬ с параметрами должен или без них могут быть кэшируемыми, поэтому вышеуказанное решение должно работать.

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

Ерунда. Строка запроса (также известная как параметры GET) является частью URL-адреса. Они могут и будут кэшироваться. Это хорошее решение.

troelskn 23.09.2008 19:39

@troelskn: В спецификации HTTP 1.1 сказано иное (в отношении запросов GET и HEAD с параметрами запроса): кеши НЕ ДОЛЖНЫ обрабатывать ответы на такие URI как свежие, если сервер не предоставляет явное время истечения срока действия. См. w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9

Michael Johnson 23.09.2008 22:52

Я пробовал использовать тип строки запроса для управления версиями со всеми основными браузерами, и они ДОЛЖНЫ кешировать файл, спецификации или нет. Однако я думаю, что лучше использовать формат style.TIMESTAMP.css, в любом случае не злоупотребляя строками запроса, потому что все еще существует вероятность того, что программное обеспечение для кеширования прокси НЕ будет кэшировать файл.

Tomas Andrle 08.10.2009 19:24

По какой-то причине стоит отметить, что сам Stackoverflow использует метод строки запроса.

jason 02.05.2010 00:13

Браузеры Android 2.2 не работают в этом случае и вообще не загружают CSS.

Petrogad 31.01.2013 01:13

@Petrogad - ну это точно ошибка в браузере андроида. Был ли отправлен отчет об ошибке?

UpTheCreek 15.04.2013 14:31

Подтвердили, что использование параметра? = Не заставит браузеры повторно загружать кешированный файл при изменении параметра. Единственный способ - программно изменить имя файла на стороне сервера, как ответил Кип.

arunskrish 02.06.2013 10:10

@boscharun: попробуйте? v = параметр ins

Marcel Burkhard 25.11.2014 16:17

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

Смотрите также:

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

Kip 23.09.2008 16:12

Вы можете принудительно выполнить «кеширование всего сеанса», если добавите идентификатор сеанса в качестве ложного параметра файла JavaScript / CSS:

<link rel = "stylesheet" src = "myStyles.css?ABCDEF12345sessionID" />
<script language = "javascript" src = "myCode.js?ABCDEF12345sessionID"></script>

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

<link rel = "stylesheet" src = "myStyles.css?20080922_1020" />
<script language = "javascript" src = "myCode.js?20080922_1120"></script>

Простая клиентская техника

В общем, кеширование - это хорошо ... Итак, есть несколько методов, в зависимости от того, решаете ли вы проблему самостоятельно при разработке веб-сайта или пытаетесь ли вы управлять кешем в производственной среде.

Обычные посетители вашего сайта не будут иметь того опыта, который вы испытываете при разработке сайта. Поскольку средний посетитель заходит на сайт реже (может быть, всего несколько раз в месяц, если вы не являетесь пользователем Google или hi5 Networks), то вероятность того, что ваши файлы будут храниться в кеше, будет ниже, и этого может быть достаточно.

Если вы хотите принудительно запустить новую версию в браузере, вы всегда можете добавить строку запроса в запрос и увеличить номер версии при внесении серьезных изменений:

<script src = "/myJavascript.js?version=4"></script>

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

С другой стороны, если вы разрабатываете веб-сайт, вы не хотите менять номер версии каждый раз, когда сохраняете изменение в разрабатываемой версии. Это было бы утомительно.

Итак, пока вы разрабатываете свой сайт, хорошим трюком будет автоматическая генерация параметра строки запроса:

<!-- Development version: -->
<script>document.write('<script src = "/myJavascript.js?dev=' + Math.floor(Math.random() * 100) + '"\></script>');</script>

Добавление строки запроса к запросу - хороший способ версии ресурса, но для простого веб-сайта это может быть ненужным. И помните, кеширование - это хорошо.

Также стоит отметить, что браузер не обязательно скупится на хранение файлов в кеше. У браузеров есть политики для такого рода вещей, и они обычно действуют по правилам, изложенным в спецификации HTTP. Когда браузер делает запрос к серверу, частью ответа является заголовок Истекает ... дата, которая сообщает браузеру, как долго он должен храниться в кеше. В следующий раз, когда браузер встречает запрос на тот же файл, он видит, что у него есть копия в кеше, и смотрит на дату Истекает, чтобы решить, следует ли его использовать.

Так что, хотите верьте, хотите нет, но на самом деле именно ваш сервер делает этот кеш браузера таким постоянным. Вы можете настроить параметры своего сервера и изменить заголовки Истекает, но небольшая техника, которую я написал выше, вероятно, намного проще для вас. Поскольку кэширование - это хорошо, вы обычно хотите установить эту дату далеко в будущее («Заголовок« Истекает срок в далеком будущем »») и использовать описанную выше технику для принудительного изменения.

Если вас интересует дополнительная информация о HTTP или о том, как эти запросы выполняются, хорошей книгой является «Высокопроизводительные веб-сайты» Стива Содерса. Это очень хорошее введение в предмет.

Быстрый трюк с генерацией строки запроса с помощью Javascript отлично работает во время активной разработки. Я сделал то же самое с PHP.

Alan Turing 21.05.2013 22:04

Это самый простой способ достичь желаемого результата оригинального плаката. Метод mod_rewrite хорошо работает, если вы хотите принудительно перезагружать файл .css или .js КАЖДЫЙ раз при загрузке страницы. Этот метод по-прежнему позволяет кэшировать, пока вы действительно не измените файл и не захотите принудительно перезагрузить его.

scott80109 19.02.2014 04:22

@keparo, у меня достаточно jquery на всех страницах, если я собираюсь изменить это вручную, это займет месяц. Если вы можете помочь мне решить все без кодирования на каждой странице.

cracker 26.11.2014 14:42

Я пробовал это решение с разными браузерами: добавляя номер версии в конце URL-адреса файла JS. Интересно, что Opera 25.0, Firefox 34.0 и Chrome 39.0.2171.65 НЕ сохранят файл в кеше, как только в конце будет номер версии, даже если номер не изменится. Однако IE 11.0 и Safari 5.1.7 работают как положено.

Chris Neve 19.01.2015 17:07

Будет ли работать этот сценарий строки запроса в отдельном файле js, а не добавляться ко всем страницам сайта, и если да, то как?

Mia Sno 06.03.2015 04:48

Если вам не повезло, вам следует подумать об использовании Date.now () вместо случайного значения.

The_Black_Smurf 01.06.2015 16:31

Кажется, это не работает для моего CSS, когда я использую: <link href='myCss.css?dev=14141'...>

Noumenon 24.07.2015 20:26

Указатели здесь были действительно удобными. У меня есть SPA, и все, что мне нужно сделать, это обновить единственный index.html при публикации. Сделать это вручную все равно было бы ужасно. Я написал код и приложение, которое это делает - я написал ответ на вопрос (который, вероятно, находится в самом конце, потому что он новый, а не потому, что он плохой), который описывает, как он работает, и включает код. Надеюсь, это поможет кому-то другому развиваться в подобных ситуациях.

statler 12.05.2016 11:26

Это лучшее и наиболее надежное решение, перечисленное по той простой причине, что оно позволяет избежать манипуляций с сервером, ненадежного кэширования заголовков HTTP и сохраняет автоматическое кеширование браузеров. Если вы начнете перехватывать сервер и переписывать URL-адреса, вы создаете потенциальный беспорядок из обращений к вашим пользователям и от них, которым не управляет. Этот простой трюк со строкой запроса используется с 1990-х годов, поэтому большинство детей не знают, что он там есть. Образы и сценарии кэша браузера и сервера изначально используют заголовки http. Вот почему маршрутизация AngularJS и прочие цирковые трюки не нужны, если вы разбираетесь в кешировании.

Stokely 30.07.2017 05:52

Это не жизнеспособное решение. Многие браузеры просто откажутся кэшировать что-либо со строкой запроса. Это причина, по которой Google, GTMetrix и аналогичные инструменты поднимают флаг, если у вас есть строки запроса по ссылкам на статический контент. Хотя это, безусловно, достойное решение для разработки, это абсолютно не решение для производства. Кроме того, кешированием управляет браузер, а не сервер. Сервер просто ПРЕДЛАГАЕТ, когда его следует обновить; браузер НЕ ДОЛЖЕН слушать сервер (и часто этого не делает). Мобильные устройства - яркий тому пример.

Nate I 24.04.2018 20:59

Решение document.write работает слишком хорошо, теперь я не могу установить точку останова в Chrome, потому что URL-адрес постоянно меняется и, таким образом, продолжает обновляться и терять мои точки останова!

CoderSteve 26.07.2019 18:30

Я предпочитаю это решение, поскольку оно не требует исправления на стороне сервера. Я больше не использую серверный код (например, .php, .asp и т. д.). Сейчас я разрабатываю строго клиентскую сторону, на сервер отправляются только вызовы ajax для получения данных, а также код js и стили css. И Chrome, похоже, относится к css, как банк к золотым слиткам. МОЙ!

Kirby L. Wallace 28.09.2019 23:51

Изменение имени файла подействует. Но обычно это не самое простое решение.

Как вы заметили, заголовок HTTP-управления кешем «no-cache» не всегда работает. Спецификация HTTP 1.1 позволяет пользовательским агентам свободно решать, запрашивать новую копию или нет. (Это не интуитивно понятно, если вы просто посмотрите на названия директив. Прочтите фактический Спецификация HTTP 1.1 для кеша ... это имеет немного больше смысла в контексте.)

Вкратце, если вы хотите использовать жесткий кеш-контроль, используйте

Cache-Control: no-cache, no-store, must-revalidate

в заголовках ваших ответов.

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

AnthonyWJones 23.09.2008 12:14

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

Bill 05.10.2008 19:16

Первое предложение может относиться к удаленный ответ da5id -«Если обновление достаточно большое / важное, я обычно меняю имя файла»..

Peter Mortensen 28.11.2020 06:50

Не используйте foo.css?version=1!

Браузеры не должны кэшировать URL-адреса с помощью переменных GET. Согласно http://www.thinkvitamin.com/features/webapps/serving-javascript-fast, хотя Internet Explorer и Firefox игнорируют это, Опера и Сафари этого не делают! Вместо этого используйте foo.v1234.css и используйте правила перезаписи, чтобы вырезать номер версии.

Во-первых, браузеры не кешируют, это функция HTTP. Зачем http заботиться о структуре URI? Есть ли официальная ссылка на спецификацию, в которой говорится, что кеширование HTTP должно понимать семантику URI, чтобы оно не кэшировало элементы со строкой запроса?

AnthonyWJones 23.09.2008 12:17

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

tzot 29.09.2008 19:47

Ссылка thinkvitamin.com не работает (домен существует, но нет репозитория).

Peter Mortensen 22.11.2020 03:58

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

Таким образом, ваш URL-адрес будет примерно таким

http://mysite.com/css/[md5_hash_here]/style.css

Вы по-прежнему можете использовать правило перезаписи для удаления хэша, но преимущество состоит в том, что теперь вы можете установить для своей политики кеширования значение «кэшировать навсегда», поскольку, если URL-адрес тот же самый, это означает, что файл не изменился.

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

Просто запускайте этот сценарий каждый раз, когда изменяется CSS, и все будет хорошо. Браузер перезагружает ваши файлы ТОЛЬКО при их изменении. Если вы внесете правку, а затем отмените ее, вам не составит труда определить, к какой версии вам нужно вернуться, чтобы посетители не могли повторно загрузить ее.

к сожалению, я не знаю, как это реализовать. Посоветуйте пожалуйста ... подробнее ...

Michael Phelps 20.10.2014 13:56

Было бы здорово реализовать в оболочке, рубине и т. д.

Peter 09.12.2014 22:28

Очень хорошее решение ... но я думаю, что для вычисления хэша файла в каждом запросе файла (css, js, images, html..etc) для каждого отдельного посещения страницы требуются ресурсы.

DeepBlue 03.05.2015 01:18

Это стандартное решение для тех, кто использует js или css в комплекте с gulp, grunt или webpack, реализация отличается для каждого решения, но хеширование ваших файлов на этапе сборки является обычным и рекомендуется для современных связанных приложений.

Brandon Søren Culley 14.04.2018 01:45

@DeepBlue - в ответе написано "запускать этот скрипт каждый раз, когда изменяется CSS". Это НЕ при каждом посещении страницы. OTOH Ответ не учитывает основные детали - как измененный хеш становится частью URL-адреса? Я не знаю...

ToolmakerSteve 15.04.2019 00:35

Используйте метку времени файла вместо хеша MD5. Все, что вам нужно, это уникальная ценность: File.GetLastWriteTime(filePath).Ticks.ToString().

Katie Kilian 29.06.2020 18:31

Недавно я решил это с помощью Python. Вот код (его легко адаптировать к другим языкам):

def import_tag(pattern, name, **kw):
    if name[0] == "/":
        name = name[1:]
    # Additional HTML attributes
    attrs = ' '.join(['%s = "%s"' % item for item in kw.items()])
    try:
        # Get the files modification time
        mtime = os.stat(os.path.join('/documentroot', name)).st_mtime
        include = "%s?%d" % (name, mtime)
        # This is the same as sprintf(pattern, attrs, include) in other
        # languages
        return pattern % (attrs, include)
    except:
        # In case of error return the include without the added query
        # parameter.
        return pattern % (attrs, name)

def script(name, **kw):
    return import_tag('<script %s src = "/%s"></script>', name, **kw)

def stylesheet(name, **kw):
    return import_tag('<link rel = "stylesheet" type = "text/css" %s href = "/%s">', name, **kw)

Этот код в основном добавляет метку времени файлов в качестве параметра запроса к URL-адресу. Вызов следующей функции

script("/main.css")

приведет к

<link rel = "stylesheet" type = "text/css"  href = "/main.css?1221842734">

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

может ли os.stat () создать узкое место?

hoju 23.07.2012 07:19

@Richard stat может стать узким местом, если диск очень медленный и запросов очень много. В этом случае вы можете кэшировать метку времени где-нибудь в памяти и очищать этот кеш при каждом новом развертывании. Тем не менее, эта сложность не понадобится в большинстве случаев использования.

pi. 23.07.2012 15:06

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

LarryBud 12.01.2021 01:43

@LarryBud: это метка времени файла, а не текущая метка времени. Кеширование обязательно будет.

pi. 14.01.2021 11:56

Допустим, у вас есть файл по адресу:

/styles/screen.css

Вы можете либо добавить параметр запроса с информацией о версии в URI, например:

/styles/screen.css?v=1234

Или вы можете добавить информацию о версии, например:

/v/1234/styles/screen.css

IMHO, второй метод лучше подходит для файлов CSS, потому что они могут ссылаться на изображения с использованием относительных URL-адресов, что означает, что если вы укажете background-image следующим образом:

body {
    background-image: url('images/happy.gif');
}

Его URL-адрес будет таким:

/v/1234/styles/images/happy.gif

Это означает, что если вы обновите номер используемой версии, сервер будет рассматривать это как новый ресурс и не будет использовать кэшированную версию. Если вы основываете свой номер версии на ревизии Subversion, CVS и т. д., Это означает, что изменения в изображениях, на которые есть ссылки в файлах CSS, будут замечены. Это не гарантируется с первой схемой, то есть URL-адрес images/happy.gif относительно /styles/screen.css?v=1235 - это /styles/images/happy.gif, который не содержит никакой информации о версии.

Я реализовал решение кэширования, используя эту технику с сервлетами Java, и просто обрабатываю запросы к /v/* с помощью сервлета, который делегирует базовый ресурс (например, /styles/screen.css). В режиме разработки я устанавливаю заголовки кеширования, которые говорят клиенту всегда проверять актуальность ресурса с сервером (обычно это приводит к 304, если вы делегируете Tomcat DefaultServlet, а файл .css, .js и т. д. Не изменился), в то время как в режиме развертывания я устанавливаю заголовки с надписью «кэш навсегда».

Простое добавление папки, которую вы можете переименовать при необходимости, будет работать, если вы используете только относительные URL-адреса. И затем убедитесь, что вы перенаправили в нужную папку из базовой папки, то есть в PHP: <?php header( 'Location: folder1/login.phtml' ); ?>.

Gruber 20.09.2012 12:56

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

TomG 06.11.2013 19:55

Предлагаю реализовать следующий процесс:

  • обновляйте свои файлы CSS и JavaScript при каждом развертывании. Что-то вроде: screen.1233.css (номер может быть вашей версией SVN, если вы используете систему управления версиями)

  • уменьшите их, чтобы оптимизировать время загрузки

Если вы используете jQuery, есть опция, называемая кешем, которая добавляет случайное число.

Я знаю это не полный ответ, но он может сэкономить вам время.

Мой способ сделать это - просто включить элемент ссылки на стороне сервера:

<!--#include virtual = "/includes/css-element.txt"-->

где содержимое css-element.txt

<link rel = "stylesheet" href = "mycss.css"/>

поэтому в тот день, когда вы захотите создать ссылку на my-new-css.css или что-то еще, вы просто измените include.

Интересный пост. Прочитав все ответы здесь в сочетании с тем фактом, что у меня никогда не было проблем с "поддельными" строками запроса (что я не уверен, почему все так неохотно используют это), я предполагаю решение (которое устраняет необходимость в правилах перезаписи Apache как в принятом ответе) заключается в вычислении короткого хэш содержимого файла CSS (вместо даты и времени файла) в качестве фиктивной строки запроса.

Это приведет к следующему:

<link rel = "stylesheet" href = "/css/base.css?[hash-here]" type = "text/css" />

Конечно, решения datetime также выполняют свою работу в случае редактирования файла CSS, но я думаю, что речь идет о содержимом файла CSS, а не о дате и времени файла, так зачем их путать?

RewriteRule нуждается в небольшом обновлении для файлов JavaScript или CSS, которые содержат в конце точечную нотацию с указанием версий. Например, json-1.3.js.

Я добавил к регулярному выражению класс отрицания точки [^.], Поэтому .number. игнорируется.

RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ . [L]

Спасибо за вклад! С тех пор, как я написал этот пост, меня это тоже обожгло. Мое решение заключалось в том, чтобы переписать только в том случае, если последняя часть имени файла содержит ровно десять цифр. (10 цифр охватывают все временные метки с 9/9/2001 по 20/11/2286.) Я обновил свой ответ, включив это регулярное выражение: ^(.*)\.[\d]{10}\.(css|js)$ .

Kip 06.08.2010 01:07

Я понимаю регулярное выражение, но не понимаю, какую проблему вы здесь решаете с [^.]. Кроме того, нет смысла писать \d внутри символьного класса - \d+ будет делать то же самое. Как было опубликовано, ваш шаблон будет соответствовать любому количеству символов (жадно), затем буквальной точке, затем без точки, затем одной или нескольким цифрам, затем точке, затем css или js, затем к концу имени файла . Не соответствует вашему образцу ввода: regex101.com/r/RPGC62/1

mickmackusa 05.12.2019 09:52

Спасибо Кип за его идеальное решение!

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

/**
 * Extend filepath with timestamp to force browser to
 * automatically refresh them if they are updated
 *
 * This is based on Kip's version, but now
 * also works on virtual hosts
 * @link http://stackoverflow.com/questions/118884/what-is-an-elegant-way-to-force-browsers-to-reload-cached-css-js-files
 *
 * Usage:
 * - extend your .htaccess file with
 * # Route for My_View_Helper_AutoRefreshRewriter
 * # which extends files with there timestamp so if these
 * # are updated a automatic refresh should occur
 * # RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ . [L]
 * - then use it in your view script like
 * $this->headLink()->appendStylesheet( $this->autoRefreshRewriter($this->cssPath . 'default.css'));
 *
 */
class My_View_Helper_AutoRefreshRewriter extends Zend_View_Helper_Abstract {

    public function autoRefreshRewriter($filePath) {

        if (strpos($filePath, '/') !== 0) {

            // Path has no leading '/'
            return $filePath;
        } elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . $filePath)) {

            // File exists under normal path
            // so build path based on this
            $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $filePath);
            return preg_replace('{\.([^./]+)$}', ".$mtime.$1", $filePath);
        } else {

            // Fetch directory of index.php file (file from all others are included)
            // and get only the directory
            $indexFilePath = dirname(current(get_included_files()));

            // Check if file exist relativ to index file
            if (file_exists($indexFilePath . $filePath)) {

                // Get timestamp based on this relativ path
                $mtime = filemtime($indexFilePath . $filePath);

                // Write generated timestamp to path
                // but use old path not the relativ one
                return preg_replace('{\.([^./]+)$}', ".$mtime.$1", $filePath);
            } else {
                return $filePath;
            }
        }
    }
}

Плагин Google mod_pagespeed для Apache сделает за вас автоматическое изменение версий. Это действительно здорово.

Он анализирует HTML на выходе с веб-сервера (работает с PHP, Рубин на рельсах, Python, статическим HTML - чем угодно) и переписывает ссылки на CSS, JavaScript, файлы изображений, чтобы они включали код идентификатора. Он обслуживает файлы по измененным URL-адресам с очень длинным контролем над ними. Когда файлы меняются, он автоматически меняет URL-адреса, поэтому браузеру приходится их повторно загружать. В основном он просто работает без каких-либо изменений в вашем коде. Он даже уменьшит ваш код на выходе.

Это здорово, но все еще в стадии бета-тестирования. Можно ли его использовать для корпоративных услуг?

Sanghyun Lee 15.07.2011 08:00

Это НЕПРАВИЛЬНО (автоматическое возня с источником), когда это явно проблема браузера. Дайте нам (разработчикам) настоящее обновление мозгов: <ctrl> + F5

T4NK3R 20.09.2011 16:50

mod_pagespeed функционально эквивалентен полностью автоматическому этапу сборки / компиляции для вашего html / css / js. Я думаю, вам будет сложно найти серьезных разработчиков, которые думают, что системы сборки ошибочны по своей сути или что нет ничего плохого в том, что они полностью автоматические. Аналогия с чистой сборкой - очистить кеш mod_pagespeed: code.google.com/p/modpagespeed/wiki/…?

Leopd 20.09.2011 21:38

@ T4NK3R mod_pagespeed не должен ничего делать с вашим источником для управления кешем, просто было упомянуто, что может помогает с такими вещами, как минимизация. Что касается того, «НЕПРАВИЛЬНО» это или нет, это полностью субъективно. Возможно, это неправильно для вас, но это не означает, что изначально это Плохо.

Madbreaks 03.08.2012 22:10

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

chirale 25.05.2013 12:52

ОЧЕНЬ ловко! В последней версии все ссылки css и js объединены в один лайнер с добавленным номером версии. Я выполнил эти инструкции для своего debian box, digitalocean.com/community/articles/…

FredTheWebGuy 26.04.2014 21:22

Он также работает с nginx, хотя вам нужно собрать его из исходного кода: developers.google.com/speed/pagespeed/module/…

Rohit 22.01.2015 10:41

@ T4NK3R - не только мы, разработчики, используем веб-сайты. Итак, ctrl + F5 - не лучшее решение для обычного пользователя, и мы не хотим, чтобы он обычно видел старую версию.

Eoin 13.02.2018 17:06

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

Я также рассчитываю это один раз для каждого файла во время выполнения (или при изменении файловой системы), поэтому во время разработки или в процессе сборки делать нечего.

Если вы используете ASP.NET MVC, вы можете проверить код в моем другом ответе здесь.

Самый простой способ - воспользоваться функцией чтения файла PHP. Просто пусть PHP выводит содержимое файла в теги.

<?php
//Replace the 'style.css' with the link to the stylesheet.
echo "<style type='text/css'>".file_get_contents('style.css')."</style>";
?>

Если вы используете что-то помимо PHP, есть некоторые вариации в зависимости от языка, но почти во всех языках есть способ распечатать содержимое файла. Поместите его в нужное место (в раздел), и тогда вам не придется полагаться на браузер.

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

Austin 03.11.2011 22:10

Ответ Тома прав.

Использование метода "querystring" не будет кэшироваться, как указано в Стив Содерс ниже:

...that Squid, a popular proxy, doesn’t cache resources with a querystring.

Предложение TomA использования style.TIMESTAMP.css - это хорошо, но MD5 будет намного лучше, поскольку только когда содержимое было действительно изменено, MD5 также изменится.

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

Luca 11.10.2012 03:40

В комментарии 2008 года к тому же сообщению в блоге упоминается, что настройки Squid по умолчанию изменились; вопрос в том, какой процент вашего трафика обрабатывается (сейчас) устаревшими версиями Squid.

TomG 06.11.2013 19:59

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

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

Я не уверен, почему вы, ребята, так стараетесь реализовать это решение.

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

В PHP я бы сделал это так:

<link href = "mycss.css?v=<?= filemtime('mycss.css') ?>" rel = "stylesheet">

filemtime () - это функция PHP, которая возвращает временную метку измененного файла.

Вы можете просто использовать mycss.css?1234567890.

Gavin 05.06.2014 03:43

очень элегантно, хотя я немного изменил его на <link rel = "stylesheet" href = "mycss.css?<?php echo filemtime('mycss.css') ?>"/>, на всякий случай некоторые аргументы в этом потоке о кешировании URL-адресов с помощью переменных GET (в предложенном формате) верны

luke_mclachlan 24.12.2015 16:52

В дополнение к моему последнему комментарию, я видел, что wordpress использует ?ver=, так что кто знает!

luke_mclachlan 24.12.2015 17:25

Отличное решение. Вдобавок я обнаружил, что filemtime не работает для полного доменного имени (FQDN), поэтому я использовал FQDN для части href и $ _SERVER ["DOCUMENT_ROOT"] для части filemtime. Пример: <link rel = "stylesheet" href = "http: //theurl/mycss.css? V = <? Php echo filemtime ($ _ SERVER [" DOCUMENT_ROOT "]. '/Mycss.css')?>" />

rrtx2000 18.08.2016 19:56

Большое спасибо. Просто и хорошо. Вот он в Python: progpath = os.path.dirname (sys.argv [0]) def versionize (file): timestamp = os.path.getmtime ('% s /../ web /% s'% (progpath , file)) return '% s? v =% s'% (file, timestamp) print <link href = "% s" rel = "stylesheet" '' type = "text / css" /> '\% versionize ( 'css / main.css')

dlink 25.12.2017 01:00

В этом подходе есть несколько ошибок. Во-первых, это полностью исключает кеширование этого файла. Вопрос требовал принудительного обновления актива, КОГДА ОНО ИЗМЕНЕНО, не предотвращая полностью кеширование (что в целом является ОЧЕНЬ плохой идеей). Во-вторых, строки запроса к статическим файлам - плохая идея, поскольку некоторые браузеры не кэшируют их вообще, другие кешируют их независимо от того, что это за строка запроса. В целом, это очень младшее решение, и вопрос, почему люди обсуждали правильное решение (в отличие от взлома), просто показывает общее непонимание этого вопроса.

Nate I 16.04.2019 18:28

Совершенно идеальное быстрое решение.

Matt 01.02.2020 02:52

"Another idea which was suggested by SCdF would be to append a bogus query string to the file. (Some Python code to automatically use the timestamp as a bogus query string was submitted by pi.) However, there is some discussion as to whether or not the browser would cache a file with a query string. (Remember, we want the browser to cache the file and use it on future visits. We only want it to fetch the file again when it has changed.) Since it is not clear what happens with a bogus query string, I am not accepting that answer."

<link rel = "stylesheet" href = "file.css?<?=hash_hmac('sha1', session_id(), md5_file("file.css")); ?>" />

Хеширование файла означает, что после его изменения изменится и строка запроса. В противном случае он останется прежним. Каждый сеанс также вызывает перезагрузку.

При желании вы также можете использовать перезапись, чтобы браузер решил, что это новый URI.

Для среды Сервлет Java вы можете посмотреть Библиотека Jawr. На странице функций объясняется, как он обрабатывает кеширование:

Jawr will try its best to force your clients to cache the resources. If a browser asks if a file changed, a 304 (not modified) header is sent back with no content. On the other hand, with Jawr you will be 100% sure that new versions of your bundles are downloaded by all clients. Every URL to your resources will include an automatically generated, content-based prefix that changes automatically whenever a resource is updated. Once you deploy a new version, the URL to the bundle will change as well so it will be impossible that a client uses an older, cached version.

Библиотека также выполняет минификацию JavaScript и CSS, но вы можете отключить это, если не хотите.

Вы можете просто добавить случайное число с URL-адресом CSS и JavaScript, например

example.css?randomNo = Math.random()

Для ASP.NET я предлагаю следующее решение с расширенными параметрами (режим отладки / выпуска, версии):

Включите файлы JavaScript или CSS следующим образом:

<script type = "text/javascript" src = "Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel = "stylesheet" type = "text/css" href = "Css/exampleCss<%=Global.CssPostfix%>" />

Global.JsPostfix и Global.CssPostfix вычисляются в Global.asax следующим образом:

protected void Application_Start(object sender, EventArgs e)
{
    ...
    string jsVersion = ConfigurationManager.AppSettings["JsVersion"];
    bool updateEveryAppStart = Convert.ToBoolean(ConfigurationManager.AppSettings["UpdateJsEveryAppStart"]);
    int buildNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision;
    JsPostfix = "";
#if !DEBUG
    JsPostfix += ".min";
#endif
    JsPostfix += ".js?" + jsVersion + "_" + buildNumber;
    if (updateEveryAppStart)
    {
        Random rand = new Random();
        JsPosfix += "_" + rand.Next();
    }
    ...
}

Другой способ для файлов JavaScript - использовать jQuery $.getScript вместе с опцией $.ajaxSetupcache: false.

Вместо:

<script src = "scripts/app.js"></script>

Вы можете использовать:

$.ajaxSetup({
  cache: false
});

$.getScript('scripts/app.js'); // GET scripts/app.js?_1391722802668

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

Kip 07.02.2014 02:18

Еще одно предложение для веб-сайтов ASP.NET,

  1. Установите разные значения cache-control:max-age для разных статических файлов.

  2. Для файлов CSS и JavaScript вероятность изменения этих файлов на сервере высока, поэтому установите минимальное значение cache-control: максимальный возраст, равное 1 или 2 минутам, или что-то еще, что соответствует вашим потребностям.

  3. Для изображений установите дальнюю дату как значение cache-control: максимальный возраст, скажем, 360 дней.

  4. Таким образом, когда мы делаем первый запрос, все статическое содержимое загружается на клиентскую машину с ответом 200-ОК.

  5. При последующих запросах и через две минуты мы видим запросы 304-Не изменено в файлах CSS и JavaScript, что позволяет нам избежать управления версиями CSS и JavaScript.

  6. Файлы изображений не будут запрашиваться, поскольку они будут использоваться из кэшированной памяти до истечения срока действия кеша.

  7. Используя приведенные ниже конфигурации web.config, мы можем добиться описанного выше поведения,

    <system.webServer>
        <modules runAllManagedModulesForAllRequests = "true"/>
        <staticContent>
            <clientCache cacheControlMode = "UseMaxAge" cacheControlMaxAge = "00.00:01:00"/>
        </staticContent>
        <httpProtocol>
            <customHeaders>
                <add name = "ETAG" value = ""/>
            </customHeaders>
        </httpProtocol>
    </system.webServer>
    
    <location path = "Images">
        <system.webServer>
            <staticContent>
                <clientCache cacheControlMode = "UseMaxAge" cacheControlMaxAge = "180.00:00:00" />
            </staticContent>
        </system.webServer>
    </location>
    

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

Подробнее см .: Использование кеша приложения

Для ASP.NET 4.5 и выше вы можете использовать пакетирование скриптов.

The request http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81 is for the bundle AllMyScripts and contains a query string pair v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81. The query string v has a value token that is a unique identifier used for caching. As long as the bundle doesn't change, the ASP.NET application will request the AllMyScripts bundle using this token. If any file in the bundle changes, the ASP.NET optimization framework will generate a new token, guaranteeing that browser requests for the bundle will get the latest bundle.

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

Пожалуйста, помогите мне, я не делаю никаких изменений в bundle.config, просто меняю файлы css или js, тогда как я могу решить проблему кеширования?

vedankita kumbhar 27.02.2017 09:43

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

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

В качестве примера приведем простой сценарий bash, который считывает список имен файлов из стандартный ввод и записывает файл JSON, содержащий хэши, в стандартный вывод:

#!/bin/bash
# Create a JSON map from filenames to MD5 hashes
# Run as hashes.sh < inputfile.list > outputfile.json

echo "{"
delim = ""
while read l; do
    echo "$delim\"$l\": \"`md5 -q $l`\""
    delim = ","
done
echo "}"

Затем этот файл можно было бы загрузить при запуске сервера и ссылаться на него вместо чтения файловой системы.

Вот чистое решение JavaScript

(function(){

    // Match this timestamp with the release of your code
    var lastVersioning = Date.UTC(2014, 11, 20, 2, 15, 10);
 
    var lastCacheDateTime = localStorage.getItem('lastCacheDatetime');

    if (lastCacheDateTime){
        if (lastVersioning > lastCacheDateTime){
            var reload = true;
        }
    }

    localStorage.setItem('lastCacheDatetime', Date.now());

    if (reload){
        location.reload(true);
    }

})();

Вышеупомянутое будет искать последний раз, когда пользователь посещал ваш сайт. Если последнее посещение было до того, как вы выпустили новый код, он использует location.reload(true) для принудительного обновления страницы с сервера.

Обычно у меня это самый первый скрипт в <head>, поэтому он проверяется перед загрузкой любого другого контента. Если потребуется перезагрузка, она вряд ли заметна пользователю.

Я использую локальное хранилище для хранения отметки времени последнего посещения в браузере, но вы можете добавить файлы cookie в смесь, если хотите поддерживать более старые версии IE.

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

DeepBlue 03.05.2015 03:29

Ответ, относящийся к SilverStripe, получен из чтения: http://api.silverstripe.org/3.0/source-class-SS_Datetime.html#98-110:

Надеюсь, это поможет кому-то, кто использует шаблон SilverStripe и пытается принудительно перезагружать кэшированное изображение при каждом посещении / обновлении страницы. В моем случае это GIF-анимация, которая воспроизводится только один раз и поэтому не воспроизводится после кэширования. В моем шаблоне я просто добавил:

?$Now.Format(dmYHis)

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

Ссылка api.silverstripe.org не работает (404).

Peter Mortensen 28.11.2020 08:02

Что касается моей разработки, я считаю, что Chrome предлагает отличное решение.

https://superuser.com/a/512833

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

Это мой лучший друг, и это очень легкий способ получить то, что вы хотите!

И если вы используете Chrome в качестве среды разработки, другим неинвазивным решением является отключение кеша: в настройках cog вы можете сделать недействительным дисковый кеш, выбрав `` Отключить кеш '' (примечание: DevTools должны быть видимыми / открытыми чтобы это работало).

Velojet 06.02.2016 00:52

Что такое "длинный щелчок"?

Peter Mortensen 28.11.2020 08:05

Ссылка (фактически) не работает. Он перенаправляет на общую страницу "Chrome DevTools" - developers.google.com/web/tools/chrome-devtools

Peter Mortensen 28.11.2020 08:05

@PeterMortensen Когда вы нажимаете и удерживаете кнопку щелчка.

Frank Bryce 13.01.2021 23:56

30 или около того существующих ответов - отличный совет для сайта примерно 2008 года. Однако, когда дело доходит до современного одностраничное приложение (SPA), возможно, пришло время переосмыслить некоторые фундаментальные предположения… в частности, идею о том, что веб-сервер желательно обслуживать только одну, самую последнюю версию файла.

Представьте, что вы пользователь, у которого в ваш браузер загружена версия M SPA:

  1. Ваш конвейер компакт диск развертывает новую версию N приложения на сервере
  2. Вы перемещаетесь в SPA, который отправляет XMLHttpRequest (XHR) на сервер, чтобы получить /some.template.
  • (Ваш браузер не обновил страницу, поэтому вы все еще используете версию M)
  1. Сервер отвечает содержимым /some.template - вы хотите, чтобы он возвращал версию M или N шаблона?

Если формат /some.template изменился между версиями M и N (или файл был переименован или что-то еще) вы, вероятно, не хотите, чтобы версия N шаблона отправлялась в браузер, в котором запущена старая версия M парсера. †

Веб-приложения сталкиваются с этой проблемой при соблюдении двух условий:

  • Ресурсы запрашиваются асинхронно через некоторое время после начальной загрузки страницы.
  • Логика приложения предполагает некоторые вещи (которые могут измениться в будущих версиях) о содержимом ресурса.

Если ваше приложение должно обслуживать несколько версий параллельно, решение кеширования и «перезагрузки» становится тривиальным:

  1. Установите все файлы сайта в каталоги с поддержкой версий: /v<release_tag_1>/…files…, /v<release_tag_2>/…files…
  2. Установите заголовки HTTP, чтобы браузеры могли кэшировать файлы навсегда
  • (Или еще лучше, поместите все в CDN)
  1. Обновите все теги <script> и <link> и т. д., Чтобы они указывали на этот файл в одном из каталогов с поддержкой версий.

Этот последний шаг звучит сложно, так как может потребоваться вызов построителя URL-адресов для каждого URL-адреса в коде на стороне сервера или на стороне клиента. Или вы можете просто разумно использовать Тег <base> и изменить текущую версию в одном месте.

† Один из способов обойти это - настойчиво заставлять браузер перезагружать все при выпуске новой версии. Но для того, чтобы завершить выполнение любых незавершенных операций, проще всего поддерживать как минимум две версии параллельно: v-current и v-previous.

Михаил - ваш комментарий очень актуален. Я здесь как раз пытаюсь найти решение для своего СПА. У меня есть подсказки, но решение пришлось искать самому. В конце концов, я был очень доволен тем, что придумал, поэтому написал сообщение в блоге и ответ на этот вопрос (включая код). Спасибо за указатели

statler 12.05.2016 11:23

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

David Casillas 30.06.2017 18:46

Отличный ответ и абсолютно идеальная стратегия! И бонусные баллы за упоминание тега base! Что касается поддержки старого кода: это не всегда возможность и не всегда хорошая идея. Новые версии кода могут поддерживать критические изменения в других частях приложения или могут включать аварийные исправления, исправления уязвимостей и т. д. Мне еще предстоит реализовать эту стратегию, но я всегда чувствовал, что общая архитектура должна позволять развертываниям помечать старую версию как obsolete и принудительно перезагружать ее при следующем асинхронном вызове (или просто принудительно деаутентифицировать все сеансы через WebSockets).

Jonny Asmar 23.12.2017 03:30

Приятно видеть хорошо продуманный ответ в отношении одностраничных приложений.

Nate I 16.04.2019 18:33

Это «сине-зеленое развертывание», если вы хотите найти дополнительную информацию.

Fil 16.07.2019 14:10

Я пришел к этому вопросу, когда искал решение для своего SPA, в котором есть только один файл index.html, в котором перечислены все необходимые файлы. Хотя у меня было несколько потенциальных клиентов, которые мне помогли, я не мог найти быстрого и легкого решения.

В конце концов, я написал быструю страницу (включая весь код), необходимую для автоматической версии файла HTML / JavaScript index.html в рамках процесса публикации. Он работает отлично и обновляет новые файлы только в зависимости от даты последнего изменения.

Вы можете увидеть мой пост на Автоверсия вашего SPA index.html. Там же есть отдельное приложение для Windows.

Внутренняя часть кода:

private void ParseIndex(string inFile, string addPath, string outFile)
{
    string path = Path.GetDirectoryName(inFile);
    HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
    document.Load(inFile);

    foreach (HtmlNode link in document.DocumentNode.Descendants("script"))
    {
        if (link.Attributes["src"]!=null)
        {
            resetQueryString(path, addPath, link, "src");
        }
    }

    foreach (HtmlNode link in document.DocumentNode.Descendants("link"))
    {
        if (link.Attributes["href"] != null && link.Attributes["type"] != null)
        {
            if (link.Attributes["type"].Value == "text/css" || link.Attributes["type"].Value == "text/html")
            {
                resetQueryString(path, addPath, link, "href");
            }
        }
    }

    document.Save(outFile);
    MessageBox.Show("Your file has been processed.", "Autoversion complete");
}

private void resetQueryString(string path, string addPath, HtmlNode link, string attrType)
{
    string currFileName = link.Attributes[attrType].Value;

    string uripath = currFileName;
    if (currFileName.Contains('?'))
        uripath = currFileName.Substring(0, currFileName.IndexOf('?'));
    string baseFile = Path.Combine(path, uripath);
    if (!File.Exists(baseFile))
        baseFile = Path.Combine(addPath, uripath);
    if (!File.Exists(baseFile))
        return;
    DateTime lastModified = System.IO.File.GetLastWriteTime(baseFile);
    link.Attributes[attrType].Value = uripath + "?v = " + lastModified.ToString("yyyyMMddhhmm");
}

Я не нашел подход к DOM на стороне клиента, динамически создающий элемент скрипта (или CSS):

<script>
    var node = document.createElement("script");
    node.type = "text/javascript";
    node.src = 'test.js?' + Math.floor(Math.random()*999999999);
    document.getElementsByTagName("head")[0].appendChild(node);
</script>

Какой имеют вы тогда нашли? Вы можете прояснить это? Желательно редактирование вашего ответа (но без "Edit:", "Update:" или подобное), а не здесь, в комментариях.

Peter Mortensen 28.11.2020 09:16

Кажется, все ответы здесь предполагают какое-то управление версиями в схеме именования, что имеет свои недостатки.

Браузеры должны хорошо знать, что кэшировать, а что нет, читая ответ веб-сервера, в частности заголовки HTTP - как долго этот ресурс действителен? Обновлялся ли этот ресурс с момента последнего его получения? и Т. Д.

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

Более подробное объяснение того, как это работает, находится в Как работают веб-кеши.

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

// Add it to the top of the page
<?php
    srand();
    $random_number = rand();
?>

Затем примените случайное число к версии JavaScript следующим образом:

<script src = "file.js?version=<?php echo $random_number;?>"></script>

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

Kip 22.08.2016 04:20

Да, пользователь должен повторно загружать файл при каждой загрузке страницы, потому что некоторый java-скрипт, включенный в (iframe), не обновляет содержимое страницы, если пользователь не нажмет F5 или не перезагрузит страницу вручную. Так что это лучшее решение для перезагрузки контента каждый раз, когда новый посетитель посещает веб-сайт.

Mizo Games 24.08.2016 00:47

Если вы используете Git и PHP, вы можете перезагружать скрипт из кеша каждый раз, когда в репозитории Git происходят изменения, используя следующий код:

exec('git rev-parse --verify HEAD 2> /dev/null', $gitLog);
echo '  <script src = "/path/to/script.js"?v='.$gitLog[0].'></script>'.PHP_EOL;

В Laravel (PHP) мы можем сделать это следующим ясным и элегантным способом (используя временную метку модификации файла):

<script src = "{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>

И аналогично для CSS

<link rel = "stylesheet" href = "{{asset('css/your.css?v='.filemtime('css/your.css'))}}">

Пример вывода HTML (время возврата filemtime как Отметка времени Unix)

<link rel = "stylesheet" href = "assets/css/your.css?v=1577772366">

что выводит эта команда в html? А что, если мне нужно обновить только такие версии, как? V = 3,? V = 4 и т. д. - не заставляет браузер загружать css каждый раз, когда пользователь входит на сайт

Gediminas 28.09.2017 08:38
filemtime: "This function returns the time when the data blocks of a file were being written to, that is, the time when the content of the file was changed." src: php.net/manual/en/function.filemtime.php
Kamil Kiełczewski 28.09.2017 14:12

Просто добавьте этот код туда, где вы хотите выполнить полную перезагрузку (заставьте браузер перезагрузить кешированные файлы CSS и JavaScript):

$(window).load(function() {
    location.reload(true);
});

Сделайте это внутри .load, чтобы он не обновлялся как цикл.

Не работает в Chrome. Все еще загружает ресурсы из кеша диска

Jason Kim 12.10.2017 21:08

В Google Chrome есть параметр Жесткая перезагрузка, а также параметр Очистить кеш и выполнить полную перезагрузку. Вы можете нажать и удерживать кнопку перезагрузки (в Режим проверки), чтобы выбрать один.

Чтобы уточнить, под «Режимом проверки» они ссылаются на «Инструменты разработчика», также известные как F12, они же ctrl + shift + i, также известные как ant menu> More Tools> Developer Tools, aka right click> Inspect Element. Также есть настройка, спрятанная где-то в инструментах разработчика (я забыл местоположение), чтобы жестко перезагружать при каждой перезагрузке.

Jonny Asmar 23.12.2017 03:20

Отключите кеширование script.jsтолько для местного развития в чистом JavaScript.

Он вводит случайный script.js? wizardry = 1231234 и блокирует обычный script.js:

<script type = "text/javascript">
  if (document.location.href.indexOf('localhost') !== -1) {
    const scr = document.createElement('script');
    document.setAttribute('type', 'text/javascript');
    document.setAttribute('src', 'scripts.js' + '?wizardry=' + Math.random());
    document.head.appendChild(scr);
    document.write('<script type = "application/x-suppress">'); // prevent next script(from other SO answer)
  }
</script>

<script type = "text/javascript" src = "scripts.js">

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

В ASP.NET:

<link rel = "stylesheet" href = "~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />

<script type = "text/javascript" src = "~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>

Это можно упростить до:

<script src = "<%= Page.ResolveClientUrlUnique("~/js/custom.js") %>" type = "text/javascript"></script>

Добавив в проект метод расширения для расширения Страница:

public static class Extension_Methods
{
    public static string ResolveClientUrlUnique(this System.Web.UI.Page oPg, string sRelPath)
    {
        string sFilePath = oPg.Server.MapPath(sRelPath);
        string sLastDate = System.IO.File.GetLastWriteTime(sFilePath).ToString();
        string sDateHashed = System.Text.RegularExpressions.Regex.Replace(sLastDate, "[^0-9]", "");

        return oPg.ResolveClientUrl(sRelPath) + "?d = " + sDateHashed;
    }
}

Небольшое улучшение по сравнению с существующими ответами ...

Использование случайного числа или идентификатора сеанса приведет к его перезагрузке при каждом запросе. В идеале нам может потребоваться внести изменения, только если некоторые изменения кода были внесены в какой-либо файл JavaScript или CSS.

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

<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core"%>
<c:set var = "version" scope = "application" value = "1.0.0" />

Теперь используйте указанную выше переменную во всех местах, как показано ниже, во включенных файлах JavaScript.

<script src='<spring:url value = "/js/myChangedFile.js?version=${version}"/>'></script>

Преимущества:

  1. This approach will help you in changing version number at one location only.
  1. Maintaining a proper version number (usually build/release number) will help you to check/verify your code changes being deployed properly (from developer console of the browser).

Еще один полезный совет:

Если вы используете браузер Chrome, вы можете отключить кеширование, когда Инструменты разработчика открыт. В Chrome нажмите F12F1 и прокрутите до НастройкиПредпочтенияСеть → * Отключить кеширование (пока DevTools открыт)

Chrome DevTools

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

Или для разработчиков: измените имена ваших файлов CSS и JavaScript, например, на версии.

<link rel = "stylesheet" href = "cssfolder/somecssfile-ver-1.css"/>

Сделайте то же самое для своих файлов JavaScript.

Вы можете использовать НИИ, чтобы сломать кеш браузера. Вам нужно только каждый раз обновлять файл index.html новым хешем SRI. Когда браузер загружает HTML и обнаруживает, что хэш SRI на странице HTML не совпадает с хешем кэшированной версии ресурса, он перезагрузит ваш ресурс с ваших серверов. У этого также есть хороший побочный эффект - обход блокировки чтения из разных источников.

<script src = "https://jessietessie.github.io/google-translate-token-generator/google_translate_token_generator.js" integrity = "sha384-muTMBCWlaLhgTXLmflAEQVaaGwxYe1DYIf2fGdRkaAQeb4Usma/kqRWFWErr2BSi" crossorigin = "anonymous"></script>

Какие браузеры, в т. версии, поддерживаете это? Ответьте, обновив свой ответ (не здесь, в комментариях).

Peter Mortensen 28.11.2020 09:50

Для разработки: используйте настройку браузера: например, Chromenetwork tab имеет параметр disable cache.

Для производства: добавьте к запросу уникальный параметр запроса (Например, q?Date.now()) с серверной структурой рендеринга или чистым кодом JavaScript.

// Pure JavaScript unique query parameter generation
//
//=== myfile.js

function hello() { console.info('hello') };

//=== end of file

<script type = "text/javascript">
    document.write('<script type = "text/javascript" src = "myfile.js?q=' + Date.now() + '">
    // document.write is considered bad practice!
    // We can't use hello() yet
</script>')

<script type = "text/javascript">
    hello();
</script>

Этот пример требует редактирования. Идея хороша, но есть путаница с тегами начала и конца сценария в приведенном выше.

Magnus 02.10.2020 11:25

Для разработчиков, у которых возникла эта проблема при разработке и тестировании:

На короткое время удалите кеширование.

"keep caching consistent with the file" .. это слишком много хлопот ..

Вообще говоря, я не против загрузки еще - даже повторная загрузка файлов, которые не изменились - в большинстве проектов - практически не имеет значения. При разработке приложения - мы в основном загружаемся с диска на localhost:port - поэтому эта проблема increase in network traffic - не проблема срыва сделки.

Большинство небольших проектов просто играют - они никогда не заканчиваются в производстве. Так что для них больше ничего не нужно ...

Таким образом, если вы используете Chrome DevTools, вы можете следовать этому подходу с отключением кеширования, как показано на изображении ниже:

How to force chrome to reload cached files

И если у вас есть проблемы с кешированием Fire Fox:

How to force asset reload on Firefox

How to disable caching in Firefox while in development

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

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

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

Jitendra Pancholi 01.04.2020 16:39

У нас есть одно решение с другим способом реализации. Мы используем для этого вышеуказанное решение.

datatables?v=1

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

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

datatables?v=Guid.NewGuid()

Последний способ, который является наилучшим:

Когда происходит изменение файла, измените и версию. Проверьте следующий код:

<script src = "~/scripts/[email protected](Server.MapPath("/scripts/main.js")).ToString("yyyyMMddHHmmss")"></script>

Таким образом, когда вы изменяете файл, LastWriteTime также изменяется, поэтому версия файла изменится, и в следующий раз, когда вы откроете браузер, он обнаружит новый файл и загрузит его.

Простое решение для статических файлов (только для целей разработки), которое добавляет случайный номер версии к URI сценария, используя инъекции тегов сценария.

<script>
    var script = document.createElement('script');
    script.src = "js/app.js?v = " + Math.random();
    document.getElementsByTagName('head')[0].appendChild(script);
</script>

Вот мое решение для очистки кеша на основе сценария Bash:

  1. Я предполагаю, что в вашем файле index.html есть ссылки на файлы CSS и JavaScript.
  2. Добавьте метку времени в качестве параметра для .js и .css в index.html, как показано ниже (только один раз)
  3. Создайте файл timestamp.txt с указанной выше меткой времени.
  4. После любого обновления файла .css или .js просто запустите приведенный ниже сценарий .sh

Пример записей index.html для .js и .css с отметкой времени:

<link rel = "stylesheet" href = "bla_bla.css?v=my_timestamp">
<script src = "scripts/bla_bla.js?v=my_timestamp"></script>

Файл timestamp.txt должен содержать только ту же временную метку my_timestamp (будет найден и заменен скриптом позже)

Наконец, вот сценарий (назовем его cache_buster.sh: D)

old_timestamp=$(cat timestamp.txt)
current_timestamp=$(date +%s)
sed -i -e "s/$old_timestamp/$current_timestamp/g" index.html
echo "$current_timestamp" >timestamp.txt

(Пользователи Visual Studio Code) вы можете поместить этот скрипт в ловушку, чтобы он вызывал каждый раз, когда файл сохраняется в вашей рабочей области.

Я решил эту проблему, используя ETag:

ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for Web cache validation, which allows a client to make conditional requests. This allows caches to be more efficient and saves bandwidth, as a Web server does not need to send a full response if the content has not changed. ETags can also be used for optimistic concurrency control,1 as a way to help prevent simultaneous updates of a resource from overwriting each other.

  • Я запускаю одностраничное приложение (написанное на Vue.JS).
  • Вывод приложения создается npm и сохраняется в папке dist (важный файл: dist / static / js / app.my_rand.js)
  • Nginx отвечает за обслуживание содержимого в этой папке dist и генерирует новое значение Etag, которое представляет собой своего рода отпечаток пальца, на основе времени модификации и содержимого папки dist. Таким образом, при изменении ресурса создается новое значение Etag.
  • Когда браузер запрашивает ресурс, сравнение заголовков запроса и сохраненного Etag может определить, являются ли два представления ресурса одинаковыми и могут ли они быть обслужены из кеша, или должен быть предоставлен новый ответ с новым Etag.

Не могли бы вы немного уточнить? Сейчас это фактически ответ только по ссылке.

Peter Mortensen 28.11.2020 11:19

Я обновил свой ответ

raul7 29.11.2020 21:00

В ASP.NET Core этого можно добиться, добавив asp-append-version:

<link rel = "stylesheet" href = "~/css/xxx.css" asp-append-version = "true" />

 <script src = "~/js/xxx.js" asp-append-version = "true"></script>

Он сгенерирует HTML:

<link rel = "stylesheet" href = "/css/xxx.css?v=rwgRWCjxemznsx7wgNx5PbMO1EictA4Dd0SjiW0S90g" />

Платформа будет генерировать новый номер версии каждый раз, когда вы обновляете файл.

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