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

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

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

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

Обновить :

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

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

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

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

Ответы

Ответ 1

Обновление: Переписано для добавления предложений от John Millikin и da5id. Это решение написано на PHP, но должно быть легко адаптировано к другим языкам.

Обновить 2: Включение комментариев от Nick Johnson, что исходное регулярное выражение .htaccess может вызвать проблемы с файлами типа json-1.3.js. Решение состоит только в переписывании, если в конце есть ровно 10 цифр. (Поскольку 10 цифр охватывают все временные метки с 9/9/2001 по 11/20/2286.)

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

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

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

/**
 *  Given a file, i.e. /css/base.css, replaces it with a string containing the
 *  file 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. В принципе все, что не динамически генерируется.

Ответ 2

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

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

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

<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. Когда браузер делает запрос на сервер, частью ответа является заголовок EXPIRES.. дата, которая сообщает браузеру, как долго он хранится в кеше. В следующий раз, когда браузер встретит запрос на тот же файл, он увидит, что он имеет копию в кеше и смотрит на дату EXPIRES, чтобы решить, следует ли ее использовать.

Так верьте или нет, это на самом деле ваш сервер, который делает этот кеш браузера настолько стойким. Вы можете настроить параметры своего сервера и изменить заголовки EXPIRES, но небольшая техника, которую я написал выше, вероятно, намного проще для вас. Поскольку кэширование является хорошим, вы обычно хотите установить эту дату далеко в будущее ( "Долгосрочный конец Expires Header" ) и использовать описанную выше методику для изменения.

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

Вы можете просто положить ?foo=1234 в конец вашего импорта css/js, изменив значение 1234 на то, что вам нравится. Посмотрите на источник SO html для примера.

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


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

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

Ответ 7

Я слышал, что это называется "автоматическое управление версиями". Самый распространенный метод - включить статический файл mtime где-то в URL-адрес и разбить его, используя обработчики перезаписи или URL confs:

См. также:

Ответ 8

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

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

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

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

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

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

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

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

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

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

Ответ 9

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

Ответ 10

RewriteRule нуждается в небольшом обновлении для js или css файлов, которые содержат концевое нотирование версий в конце. Например. JSON-1.3.js.

Я добавил класс повторения точки [^.] в regex так .number. игнорируется.

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

Ответ 11

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

Запрос http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81 предназначен для пакета AllMyScripts и содержит пару строк запроса v = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81. Строка запроса v имеет токен значения, который является уникальным идентификатором, используемым для кэширования. Пока пакет не изменится, приложение ASP.NET запросит пакет AllMyScripts, используя этот токен. Если какой-либо файл в пакете изменится, инфраструктура оптимизации ASP.NET создаст новый токен, гарантирующий, что запросы браузера для пакета получат последний пакет.

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

Ответ 12

Вот чистое решение для 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) для принудительного обновления страницы с сервера.

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

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

Ответ 13

В 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'))}}">

Ответ 14

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

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

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

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

Ответ 15

Для моего развития я считаю, что хром имеет отличное решение.

https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload

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

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

Ответ 16

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

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

Надеюсь, что это тоже поможет кому-то другому.

/**
 * Extend filepath with timestamp to force browser to
 * automatically refresh them if they are updated
 *
 * This is based on Kip 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)$ $1.$2 [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;
            }
        }
    }

}

Приветствия и благодарности.

Ответ 17

Не удалось найти сторонний подход DOM для клиента, создав динамический элемент script node (или 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>

Ответ 18

Google Chrome имеет Hard Reload, а также параметр Пустой кэш и жесткий перезапуск. Вы можете нажать и удерживать кнопку перезагрузки (в режиме проверки), чтобы выбрать ее.

Ответ 19

Вы можете принудительно выполнить "кеширование по всему сеансу", если вы добавите идентификатор сеанса в качестве аргумента sys файла в jQuery:

<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>

Ответ 20

Скажите, что у вас есть файл, доступный по адресу:

/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/etc. это означает, что будут замечены изменения изображений, упомянутых в файлах CSS. Это не гарантируется первой схемой, т.е. URL images/happy.gif относительно /styles/screen.css?v=1235 является /styles/images/happy.gif, который не содержит информации о версии.

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

Ответ 21

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

example.css?randomNo=Math.random()

Ответ 22

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

Js или 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();
    }
    ...
}

Ответ 23

Недавно я решил это с помощью 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 type="text/javascript" """ +\
        """ %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 автоматически приведет к недействительности кэша. Работает очень хорошо, и накладные расходы не заметны.

Ответ 24

Если вы используете 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;

Ответ 25

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

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

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

Более подробное объяснение того, как это работает, здесь https://www.mnot.net/cache_docs/#WORK

Ответ 26

Просто добавьте этот код, где вы хотите выполнить жесткую перезагрузку (заставить браузер перезагрузить кэшированные файлы CSS/JS). Сделайте это внутри.load, чтобы он не обновлялся, как цикл

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

Ответ 27

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

В ASP.NET

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

<script type="text/javascript" src="~/js/[email protected](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;
    }
}

Ответ 28

Я предлагаю выполнить следующий процесс:

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

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

Ответ 29

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

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

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

Ответ 30

Извините за возвращение мертвой нити.

@TomA является правильным.

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

... что Squid, популярный прокси, не кэширует ресурсы с помощью Строка запроса.

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