Як змусити клієнтів оновити файли JavaScript?


595

Наразі ми працюємо в приватній бета-версії, тому все ще вносимо досить швидкі зміни, хоча, очевидно, коли використання починає наростати, ми сповільнимо цей процес. Зважаючи на це, одна з проблем, з якою ми стикаємося, полягає в тому, що після видалення оновлення з новими файлами JavaScript клієнтські браузери все ще використовують кешовану версію файлу, і вони не бачать оновлення. Очевидно, що під час виклику служби підтримки ми можемо просто повідомити їх, щоб ctrlF5оновити оновлення, щоб вони отримували актуальні файли з сервера, але бажано було б обробити це до цього часу.

Наша теперішня думка полягає в тому, щоб просто приєднати номер версії до імені файлів JavaScript, а потім, коли будуть внесені зміни, збільшити версію на скрипт та оновити всі посилання. Це безумовно робить роботу, але оновлення посилань на кожен реліз може стати громіздким.

Оскільки я впевнений, що ми не перші, хто займається цим, я подумав, що викину це громаді. Як ви забезпечуєте, щоб клієнти оновлювали кеш-пам'ять під час оновлення коду? Якщо ви використовуєте описаний вище метод, чи використовуєте ви процес, який спрощує зміни?


Відповіді:


529

Наскільки я знаю, загальним рішенням є додавання ?<version>до src-посилання сценарію.

Наприклад:

<script type="text/javascript" src="myfile.js?1500"></script>

Я припускаю, що на даний момент немає кращого способу, ніж знайти-замінити для збільшення цих "номерів версій" у всіх тегах сценарію?

Можливо, система контролю версій зробить це для вас? Більшість систем контролю версій, наприклад, автоматично вводить номер редакції під час реєстрації.

Це виглядатиме приблизно так:

<script type="text/javascript" src="myfile.js?$$REVISION$$"></script>

Звичайно, завжди є кращі рішення, як це .


5
Хтось знає, якщо IE7 це ігнорує? Здається, ігноруючи додані дані та використовуючи кешований файл, коли я перевіряю в режимі порівняння IE8.
Шейн Рейстл

4
Я завжди знав, що рядки запиту - пара ключ-значення, як у? Ver = 123. Дякую! :)
Анкур-м

6
Я думаю, що мова не йде про більший чи нижчий номер версії, а про зміну доданого змінного значення на те, що браузер ще не міг кешувати.
Макс Гіркенс

2
Нещодавно ми стикалися з тією ж проблемою, і найкраще, що я міг придумати, - це проста функція, яка додала "? Mod = 123456", де 123456 була часовою міткою unix зміненої дати у файлі. Це, здається, виправляє проблеми, зберігаючи кешування, де це можливо. Однак я все ще бачив, як браузери ігнорують цю директиву і все одно використовують старий JS, але я не знаю, що існує елегантний "повний виправлення".
VPel

31
Для усвідомлення: це вважається злом. Цей метод наводить браузер на думку, що новий файл задається, оскільки він просто переглядає повне ім'я файлу, не інтерпретуючи його. foo.js?1- це не та сама назва, як foo.js?2браузер подумає, що це два різні файли. Недоліком є ​​те, що обидва файли будуть одночасно існувати в кеші користувачів, займаючи зайве місце.
Лі Білий

88

Додавання поточного часу до URL - це справді поширене рішення. Однак ви також можете керувати цим на рівні веб-сервера, якщо цього хочете. Сервер може бути налаштований для надсилання різних заголовків HTTP для файлів javascript.

Наприклад, щоб змусити файл кешувати не більше 1 дня, ви надішлете:

Cache-Control: max-age=86400, must-revalidate

Для бета-версії, якщо ви хочете змусити користувача завжди отримувати останню інформацію, ви використовуєте:

Cache-Control: no-cache, must-revalidate

3
чи можете ви бути більш конкретними?
Крекер

6
Він говорить про заголовки, що надсилаються веб-сервером для кожного файлу. Потрібно, наприклад, налаштовуватися в Apache. Я думаю, це було б найкращим підходом
П'єр де ЛЕСПІНАЙ

1
де ви це налаштовуєте?
Дієго

2
Для веб-розробки, можливо, це вдале рішення. Для виробничого сайту, на якому ви не хочете назавжди скасувати кеш, це не гарне рішення, якщо ви не знаєте, що кожен браузер цільового клієнта прийшов на сайт. Це змушує мене думати про потенційну функцію веб-сервера: адаптувати параметр max-age відповідно до налаштованої дати розгортання. Це було б чудово.
Клод Бріссон

Chrome ЗАПОВІДАЄ ці налаштування, щоб кешувати належним чином. Без них Chrome буде кешувати файл назавжди. Mozilla використовує набагато розумніший дефолт. Дивіться більше на: agiletribe.wordpress.com/2018/01/29/caching-for-chrome
AgilePro

42

Google Page-Speed: Не включайте рядок запиту в URL для статичних ресурсів. Більшість проксі-сервісів, особливо поміщені на версії 3.0, не кешують ресурси з "?" у їхній URL-адресі, навіть якщо у відповіді присутній заголовок кеш-керування: публічний. Щоб увімкнути кешування проксі для цих ресурсів, видаліть рядки запитів із посилань на статичні ресурси та замість цього закодуйте параметри в самі імена файлів.

У цьому випадку ви можете включити версію в URL-адресу ex: http://abc.com/ v1.2 /script.js і використовувати apache mod_rewrite для перенаправлення посилання на http://abc.com/script.js . Після зміни версії браузер клієнта оновить новий файл.


Я спробував? рішення і в IE8, і я отримую помилку javascript. Переписувати моду - це варіант, але в більшості випадків ми не маємо такого контролю над сервером. Я вважаю за краще додавати версію до самого файлу js або мати папку для кожної версії
Karthik Sankar

@ Hắc Huyền Minh: Але коли сценарій буде перезавантажений, його не слід перезавантажувати з проксі-кешу ...
Стефан Штайгер

34

Це використання призупинено: https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache

Ця відповідь запізнюється лише на 6 років, але я не бачу такої відповіді в багатьох місцях ... HTML5 запровадив кеш-програм, який використовується для вирішення цієї проблеми. Я виявив, що новий код сервера, про який я писав, зламав старий JavaScript, який зберігається в браузерах людей, тому я хотів знайти спосіб закінчення терміну дії їх JavaScript. Використовуйте файл маніфесту, який виглядає приблизно так:

CACHE MANIFEST
# Aug 14, 2014
/mycode.js

NETWORK:
*

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


Це рішення справді добре, доки ви пам’ятаєте оновлювати файл маніфесту :)
Mattis

24
Будь ласка, прочитайте документацію, оскільки ця функція була видалена з веб-стандартів developer.mozilla.org/en-US/docs/Web/HTML/…
Flavia Obreja

1
FWIW, я не скористався цим рішенням. Набагато простіше було використовувати / підтримувати ?<version> підхід.
амос

28

Як щодо додавання розміру файлів як параметра завантаження?

<script type='text/javascript' src='path/to/file/mylibrary.js?filever=<?=filesize('path/to/file/mylibrary.js')?>'></script>

Тому щоразу, коли ви оновлюєте файл, параметр "filever" змінюється.

Як щодо того, коли ви оновлюєте файл та результати оновлення в тому ж розмірі файлу? які шанси?


4
Тут використовуються теги PHP, і якщо хтось використовує PHP, це справді гарна ідея.
Джертер

1
Я думаю, що додавати зміни можна було б краще, ніж розмір файлів :)
Mazz

2
Моя початкова думка - додати хеш файлу замість версії.
Майк Чіл

Я припускаю, що він також працює, якщо додати часову марку Unix, правда? напр. '... file.js? filever = <? = час ()?>
garanda

3
використовувати filemtime ($ файл), він виводить часову позначку файлу, з часом () ви не можете використовувати кеш, оскільки він змінюється кожні секунди.
neoteknic

19

Не всі браузери кешують файли із написом "?" у цьому. Що я зробив, щоб переконатися, що він був кешований максимально, я включив версію у ім’я файлу.

Тому замість цього stuff.js?123я зробивstuff_123.js

Я використовував mod_redirect(я думаю) в apache to have stuff_*.jsto gostuff.js


Не могли б ви детальніше розібратися з тим, що ви робили в .htaccess з mod_redirect?
Венкат Д.

3
Детальне пояснення цього методу можна знайти на сайті particletree.com/notebook/…
Karl Bartel

3
Було б чудово, якби ви могли включити свій .htaccessкод у відповідь для подальшого ознайомлення.
Fizzix

1
Які браузери не кешують файли з "?" у цьому?
rosell.dk

13

Для сторінок ASP.NET я використовую наступне

ПЕРЕД

<script src="/Scripts/pages/common.js" type="text/javascript"></script>

ПІСЛЯ (примусове перезавантаження)

<script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

Додавання DateTime.Now.Ticks працює дуже добре.


31
Це суперечить усім механізмам кешування на стороні клієнта. параметр манекена слід замінити чимось на кшталт "{major version} _ {minor_version} _ {build_number} _ {Revision}, який був би унікальним для кожного випуску.
Tohid

14
Хоча це, мабуть, рішення Бога в умовах розвитку, воно не підходить для виробництва. Це повністю відключить кеш-пам'ять кожного разу при завантаженні сторінки для файлу. Уявіть завантаження сторінки на 10 кб на день з одним файлом 50 Кбіт, це щодня представляє 500 Мб файлу Javascript.
PhilDulac

@PhilDulac ви можете змінити його з Ticks, щоб повернути значення рядка дня, наприклад, місяця або тижня місяця. Зрештою, це просто показує вам, як використовувати підхід? V
alex

3
@alex Дійсно. Я просто хотів попередити, що якщо використання, продемонстроване у відповіді, пробивається до виробництва, це може мати наслідки, які не виявляться у розвитку.
PhilDulac

2
Можливим способом гарантувати, що нові копії завантажуються раз на день, може бути тип "<script src =" / Scripts / pages / common.js? Ver <% = DateTime.Now.ToString ("yyyyMMdd")%> " = "текст / javascript"> </script> '. Отже, це завантажується один раз на початку дня, потім кешується.
Робд Садлер

7

Для 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();
    }
    ...
}

Я використовую .Ticks (див. Мою відповідь на цій сторінці)
Раві Рам,

5

Загальна практика в даний час полягає в генерації хеш-коду вмісту як частини імені файлу, щоб змусити браузер, особливо IE, перезавантажувати файли javascript або файли css.

Наприклад,

продавець. a7561fb0e9a071baadb9 .js
main. b746e3eb72875af2caa9 .js

Зазвичай це робота для інструментів збирання, таких як webpack. Ось більше деталей , якщо хто -то хоче спробувати , якщо ви використовуєте Webpack.


4

Якщо ви генеруєте сторінку, що посилається на файли JS, простим рішенням додається остання часова мітка файлу до створених посилань.

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


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

3

Функцію jQuery getScript можна також використовувати для того, щоб js-файл дійсно завантажувався щоразу, коли сторінка завантажується.

Ось як я це зробив:

$(document).ready(function(){
    $.getScript("../data/playlist.js", function(data, textStatus, jqxhr){
         startProgram();
    });
});

Перевірте функцію на веб-сторінці http://api.jquery.com/jQuery.getScript/

За замовчуванням $ .getScript () встановлює значення кешу на false. Це додає до URL-адреси запиту параметр запиту, який зазначається часом, щоб переконатися, що браузер завантажує скрипт щоразу, коли його запитують.


8
Нам потрібно кешувати файли, якщо жодних змін не відбудеться.
Лео Лі

3

На PHP :

function latest_version($file_name){
    echo $file_name."?".filemtime($_SERVER['DOCUMENT_ROOT'] .$file_name);
}

В HTML :

<script type="text/javascript" src="<?php latest_version('/a-o/javascript/almanacka.js'); ?>">< /script>

Як це працює:

У HTML напишіть filepathта ім’я так, як це робите, але лише у функції. PHP отримує filetimeфайл і повертає filepath+name+"?"+timeостанню зміну


3

Ми створювали SaaS для користувачів і надавали їм сценарій для долучення до сторінки їх веб-сайту, і не вдалося приєднати версію до сценарію, оскільки користувач додасть сценарій до свого веб-сайту для функціональності, і я не можу їх змусити змінювати версію кожного разу, коли ми оновлюємо сценарій

Отже, ми знайшли спосіб завантажувати новішу версію сценарію щоразу, коли користувач викликає оригінальний сценарій

посилання сценарію, надане користувачеві

<script src="https://thesaasdomain.com/somejsfile.js" data-ut="user_token"></script>

файл сценарію

if($('script[src^="https://thesaasdomain.com/somejsfile.js?"]').length !== 0) {
   init();
} else {
   loadScript("https://thesaasdomain.com/somejsfile.js?" + guid());
}

var loadscript = function(scriptURL) {
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = scriptURL;
   head.appendChild(script);
}

var guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

var init = function() {
    // our main code
}

Пояснення:

Користувач додав сценарій, наданий їм на своєму веб-сайті, і ми перевірили, чи існує унікальний маркер, доданий до сценарію, існує чи не використовується селектор jQuery, і якщо ні, то завантажувати його динамічно новішим маркером (або версією)

Це виклик одного і того ж сценарію двічі, що може бути проблемою продуктивності, але це дійсно вирішує проблему змусити скрипт не завантажуватися з кешу, не розміщуючи версію у фактичному посиланні сценарію, наданому користувачеві або клієнту

Відмова від відповідальності: Не використовуйте, якщо продуктивність є великою проблемою у вашому випадку.


2

У mpc asp.net ви можете використовувати @ DateTime.UtcNow.ToString () для номера версії файлу js. Номер версії автоматично змінюється з датою, і ви змушуєте браузера клієнтів автоматично оновлювати файл js. Я використовую цей метод, і це добре працює.

<script src="~/JsFilePath/JsFile.js?v=@DateTime.UtcNow.ToString()"></script>

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

Ви можете використовувати код нижче зі своєї причини, кешуйте файл із номером версії <script src = "~/JsFilePath/JsFile.js?v=@GetAppVersionNumber ()"> </script>
dragonal

2

location.reload (правда);

див. https://www.w3schools.com/jsref/met_loc_reload.asp

Я динамічно закликаю цей рядок коду, щоб переконатися, що javascript було відновлено з веб-сервера замість кешу браузера, щоб уникнути цієї проблеми.


Додавання onload="location.reload();"до моєї форми дозволяє мені отримати новий JS після оновлення, а не перезавантажувати сторінку. Це куди більш елегантне рішення. Дякую!
ZX9

Дякуємо, міг би це використати для перевірки, чи розпізнається ip, але він не використовувався для входу з моменту останнього оновлення, виконайте це на сторінці індексу після початкового входу користувачів.
Fi Horan

onload = "location.reload (вірно);" Вищезазначене не працювало для мене (використовуючи колбу та поточну версію Chrome) також: w3schools.com/jsref/met_loc_reload.asp
aspiringGuru

1

Одне рішення - додавати рядок запиту із часовою позначкою до нього до URL-адреси під час отримання ресурсу. Це використовує той факт, що браузер не кешуватиме ресурси, вилучені з URL-адрес із рядками запитів.

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

Найпоширенішим рішенням, здається, є вставка часової позначки або ревізійного номера у самому імені файлу. Це трохи більше роботи, тому що ваш код потрібно змінити, щоб вимагати правильних файлів, але це означає, що, наприклад, версія 7 вашого snazzy_javascript_file.js(тобто snazzy_javascript_file_7.js) кешована в браузері до випуску версії 8, а потім ваш код змінюється на отримувати snazzy_javascript_file_8.jsнатомість.


1

Перевага використання file.js?V=1над a fileV1.jsє те, що вам не потрібно зберігати на сервері кілька версій файлів JavaScript.

Проблема, з якою я бачу, file.js?V=1полягає в тому, що у вас може бути залежний код в іншому файлі JavaScript, який порушується при використанні нової версії утиліти бібліотеки.

З метою зворотної сумісності, я думаю, що набагато краще використовувати jQuery.1.3.jsдля своїх нових сторінок і нехай використовувати існуючі сторінки jQuery.1.1.js, поки ви не будете готові оновити старі сторінки, якщо це необхідно.


1

Використовуйте GETзмінну версії, щоб запобігти кешування браузера.

Додавання ?v=AUTO_INCREMENT_VERSIONдо кінця URL-адреси запобігає кешування браузера - уникаючи будь-яких кешованих сценаріїв.


1

Мій колега щойно знайшов посилання на цей метод одразу після того, як я опублікував (з посиланням на css) на http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/ . Приємно бачити, що інші користуються цим і, здається, працює. Я припускаю, що на даний момент немає кращого способу, ніж знайти-замінити для збільшення цих "номерів версій" у всіх тегах сценарію?



1

Перестановка кешу в ASP.NET Core за допомогою помічника тегів допоможе це зробити для вас і дозволить вашому браузеру зберігати кешовані сценарії / css, поки файл не зміниться. Просто додайте помічник тегу asp-append-version = "true" у свій скрипт (js) або тег link (css):

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

У Дейва Пакетта є хороший приклад та пояснення перетворення кешу тут (внизу сторінки) Перетворення кешу


Це не працює в звичайному ASP.NET? Я спробував додати asp-append-версію до свого тегу сценарію, і все, що бачить браузер, є тегом сценарію саме так, як він з’являється у джерелі, включаючи атрибут asp-append-version.
tolsen64

Це атрибут .NET Core, пов’язаний з помічниками тегів. Він додає назву сценарію до версії, щоб сервер / браузер завжди бачив останню версію та завантажував
ccherwin

0

Найпростіше рішення? Не дозволяйте браузеру кешувати взагалі. Додайте поточний час (у мс) як запит.

(Ви все ще перебуваєте в бета-версії, тож ви можете зробити розумний випадок, коли ви не оптимізуєте продуктивність. Але YMMV тут.)


13
ІМХО - це погане рішення. Що робити, якщо ви не перебуваєте в бета-версії, і ви висуваєте важливе оновлення?
d -_- b

0

Один простий спосіб. Редагувати htaccess

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} \.(jpe?g|bmp|png|gif|css|js|mp3|ogg)$ [NC]
RewriteCond %{QUERY_STRING} !^(.+?&v33|)v=33[^&]*(?:&(.*)|)$ [NC]
RewriteRule ^ %{REQUEST_URI}?v=33 [R=301,L]

Це спричиняє перенаправлення, що є оптимальним, але неоптимальним, але робочим рішенням.
twojr

0

Нижче працювали для мене:

<head>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0" />
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
</head>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.