Come posso forzare i client ad aggiornare i file JavaScript?


596

Attualmente stiamo lavorando in una beta privata e quindi siamo ancora in procinto di apportare modifiche abbastanza rapide, anche se ovviamente mentre l'utilizzo sta iniziando a crescere, rallenteremo questo processo. Detto questo, un problema che stiamo riscontrando è che dopo aver inviato un aggiornamento con nuovi file JavaScript, i browser client utilizzano ancora la versione memorizzata nella cache del file e non vedono l'aggiornamento. Ovviamente, su una chiamata di supporto, possiamo semplicemente informarli di fare un ctrlF5aggiornamento per assicurarsi che ottengano i file aggiornati dal server, ma sarebbe preferibile gestirlo prima di quel momento.

Il nostro pensiero attuale è semplicemente quello di collegare un numero di versione al nome dei file JavaScript e quindi, quando vengono apportate modifiche, incrementare la versione sullo script e aggiornare tutti i riferimenti. Questo sicuramente porta a termine il lavoro, ma l'aggiornamento dei riferimenti su ogni versione potrebbe risultare complicato.

Dato che sono sicuro che non saremo i primi a occuparcene, ho pensato di buttarlo fuori dalla comunità. In che modo stai assicurando ai clienti di aggiornare la loro cache quando aggiorni il tuo codice? Se stai usando il metodo sopra descritto, stai usando un processo che semplifica la modifica?


Risposte:


529

Per quanto ne so, una soluzione comune è quella di aggiungere un ?<version>al link src dello script.

Per esempio:

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

Presumo a questo punto che non esiste un modo migliore di trovare-sostituire per incrementare questi "numeri di versione" in tutti i tag di script?

Potresti avere un sistema di controllo della versione per te? La maggior parte dei sistemi di controllo della versione ha un modo per iniettare automaticamente il numero di revisione al momento del check-in.

Sarebbe simile a questo:

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

Certo, ci sono sempre soluzioni migliori come questa .


5
Qualcuno sa se IE7 lo ignora? Sembra ignorare i dati aggiunti e utilizzare il file memorizzato nella cache quando eseguo il test nella vista di comparabilità di IE8.
Shane Reustle,

4
Ho sempre saputo che le stringhe di query sono coppie chiave-valore come in? Ver = 123. Grazie! :)
Ankur-m,

6
penso che non si tratti di un numero di versione superiore o inferiore, ma di cambiare il valore delle variabili aggiunte in qualcosa che il browser non avrebbe potuto ancora memorizzare nella cache.
Max Girkens,

2
Di recente abbiamo riscontrato lo stesso problema e la migliore che ho potuto trovare era una semplice funzione che collegava "? Mod = 123456" in cui 123456 era il timestamp unix della data modificata sul file. Ciò sembra risolvere i problemi pur consentendo la memorizzazione nella cache, se del caso. Tuttavia, ho ancora visto browser completamente ignorare questa direttiva e utilizzare comunque il vecchio JS, ma non so che esiste un'elegante "soluzione completa".
VPel

32
Per consapevolezza: questo è considerato un trucco. Questo metodo induce il browser a pensare che sia stato specificato un nuovo file, poiché guarda semplicemente il nome completo del file senza interpretarlo. foo.js?1non è lo stesso nome di foo.js?2, quindi il browser penserà che siano due file diversi. Un aspetto negativo è che entrambi i file saranno contemporaneamente presenti nella cache degli utenti, occupando spazio non necessario.
Lee White,

89

Aggiungere l'ora corrente all'URL è davvero una soluzione comune. Tuttavia, puoi anche gestirlo a livello di server Web, se lo desideri. Il server può essere configurato per inviare diverse intestazioni HTTP per file javascript.

Ad esempio, per forzare la memorizzazione nella cache del file per non più di 1 giorno, dovrai inviare:

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

Per la beta, se vuoi forzare l'utente a ricevere sempre le ultime novità, utilizzeresti:

Cache-Control: no-cache, must-revalidate

3
puoi per favore essere più specifico?
Kreker,

7
Sta parlando delle intestazioni inviate dal web server per ogni file. Dovrebbe essere configurabile in Apache per esempio. Penso che questo sarebbe il miglior approch
Pierre de LESPINAY il

1
dove lo configuri?
Diego,

2
Per una webapp di sviluppo, è forse una buona soluzione. Per un sito di produzione, in cui non si desidera invalidare per sempre la cache, non è una buona soluzione a meno che non si sappia che ogni browser client di destinazione è arrivato al sito. Mi viene in mente una potenziale funzionalità del web server: adattare il parametro max-age in base a una data di implementazione configurata. Sarebbe fantastico.
Claude Brisson,

Chrome RICHIEDE queste impostazioni per memorizzare correttamente nella cache. Senza di essi, Chrome memorizzerà nella cache un file per sempre. Mozilla utilizza un valore predefinito molto più ragionevole. Vedi di più su: agiletribe.wordpress.com/2018/01/29/caching-for-chrome
AgilePro

42

Google Page-Speed: non includere una stringa di query nell'URL per risorse statiche. La maggior parte dei proxy, in particolare Squid up fino alla versione 3.0, non memorizza nella cache le risorse con un "?" nel loro URL anche se è presente un controllo Cache: nella risposta è presente un'intestazione pubblica. Per abilitare la memorizzazione nella cache del proxy per queste risorse, rimuovere le stringhe di query dai riferimenti a risorse statiche e codificare invece i parametri nei nomi dei file stessi.

In questo caso, puoi includere la versione nell'URL es: http://abc.com/ v1.2 /script.js e utilizzare apache mod_rewrite per reindirizzare il collegamento a http://abc.com/script.js . Quando si modifica la versione, il browser client aggiornerà il nuovo file.


Ho provato il? soluzione e in IE8 e ottengo un errore javascript. La riscrittura delle mod è un'opzione, ma nella maggior parte dei casi non avremo molto controllo sul server. Preferirei aggiungere la versione nel file js stesso o avere una cartella per ogni versione
Karthik Sankar,

@ Hắc Huyền Minh: Ma quando lo script deve essere ricaricato, non deve essere ricaricato dalla cache del proxy ...
Stefan Steiger,

34

Questo utilizzo è stato privato: https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache

Questa risposta è in ritardo di soli 6 anni, ma non vedo questa risposta in molti luoghi ... HTML5 ha introdotto la cache dell'applicazione che viene utilizzata per risolvere questo problema. Stavo scoprendo che il nuovo codice server che stavo scrivendo stava causando il crash del vecchio javascript memorizzato nei browser delle persone, quindi volevo trovare un modo per far scadere il loro javascript. Utilizzare un file manifest simile al seguente:

CACHE MANIFEST
# Aug 14, 2014
/mycode.js

NETWORK:
*

e genera questo file con un nuovo timestamp ogni volta che desideri che gli utenti aggiornino la loro cache. Come nota a margine, se aggiungi questo, il browser non verrà ricaricato (anche quando un utente aggiorna la pagina) fino a quando il manifest non glielo dice.


Questa soluzione è davvero valida, purché ti ricordi di aggiornare il file manifest :)
Mattis,

24
Leggere la documentazione poiché questa funzione è stata rimossa dagli standard Web developer.mozilla.org/en-US/docs/Web/HTML/…
Flavia Obreja,

1
FWIW, ho finito per non usare questa soluzione. È stato molto più facile utilizzare / mantenere l' ?<version> approccio.
amos,

28

Che ne dici di aggiungere la dimensione del file come parametro di caricamento?

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

Quindi ogni volta che aggiorni il file cambia il parametro "filever".

Che ne dici di quando aggiorni il file e il tuo aggiornamento ha lo stesso file? quali sono le probabilità?


4
Questo utilizza tag PHP e se uno usa PHP, è davvero una buona idea.
Jerther,

1
Penso che aggiungere la modifica sarebbe meglio della dimensione del file :)
Mazz,

2
Il mio pensiero iniziale è quello di aggiungere un hash del file invece della versione.
Mike Cheel,

Presumo che funzioni anche se aggiungi un timestamp Unix, giusto? es. '... file.js? filever = <? = time ()?>
garanda,

3
usa filemtime ($ file) genera il timestamp del file, con time () non puoi usare la cache perché cambia ogni secondo.
neoteknic,

19

Non tutti i browser memorizzano nella cache i file con "?" dentro. Quello che ho fatto per assicurarmi che fosse il più possibile memorizzato nella cache, ho incluso la versione nel nome del file.

Quindi, invece di stuff.js?123, l'ho fattostuff_123.js

Ho usato mod_redirect(penso) in Apache have stuff_*.jsper andarestuff.js


Potresti per favore approfondire cosa hai fatto in .htaccess con mod_redirect?
Venkat D.

3
Una spiegazione dettagliata di questo metodo è disponibile su particletree.com/notebook/…
Karl Bartel,

3
Sarebbe bello se potessi includere il tuo .htaccesscodice nella tua risposta per riferimento futuro.
Fizzix,

1
Quali browser non memorizzano nella cache i file con "?" dentro?
rosell.dk,

13

Per le pagine ASP.NET sto usando quanto segue

PRIMA

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

DOPO (ricarica forzata)

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

L'aggiunta di DateTime.Now.Ticks funziona molto bene.


31
Questo va contro tutto il meccanismo di memorizzazione nella cache sul lato client. il parametro dummy dovrebbe essere sostituito con qualcosa come "{versione principale} _ {minor_version} _ {build_number} _ {Revision} che sarebbe unico per ogni versione.
Tohid

14
Sebbene questa sia probabilmente una soluzione divina in un ambiente di sviluppo, non è adatta alla produzione. Ciò disabiliterà completamente la cache ogni volta che la pagina viene caricata per il file. Immagina un caricamento di 10k pagine al giorno con un file da 50 KB, che rappresenta 500 MB di file Javascript su base giornaliera.
PhilDulac,

@PhilDulac è possibile modificarlo da Ticks per restituire il valore di stringa del giorno, ad esempio, o del mese o della settimana del mese. Alla fine ti sta solo mostrando come usare l'approccio? V
alex

3
@alex Effettivamente. Volevo solo avvertire che se l'uso dimostrato nella risposta si fa strada verso la produzione, può avere impatti che non si manifestano nello sviluppo.
PhilDulac,

2
Un modo possibile per garantire che le nuove copie vengano caricate una volta al giorno potrebbe essere l'uso del tipo "<script src =" / Scripts / pages / common.js? Ver <% = DateTime.Now.ToString ("yyyyMMdd")%> " = "text / javascript"> </ script>'. Quindi viene caricato una volta all'inizio del giorno, quindi memorizzato nella cache.
Robb Sadler,

7

Per ASP.NET suppongo che la prossima soluzione con opzioni avanzate (modalità debug / release, versioni):

File Js o Css inclusi in questo modo:

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

Global.JsPostfix e Global.CssPostfix vengono calcolati nel modo seguente in 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();
    }
    ...
}

Sto usando .Ticks (vedi la mia risposta in questa pagina)
Ravi Ram

5

La pratica comune al giorno d'oggi è quella di generare un codice hash del contenuto come parte del nome del file per forzare il browser, in particolare IE, a ricaricare i file javascript o css.

Per esempio,

fornitore. a7561fb0e9a071baadb9 .js
main. b746e3eb72875af2caa9 .js

In genere è il lavoro per gli strumenti di costruzione come il webpack. Ecco maggiori dettagli se qualcuno vuole provare se stai usando il webpack.


4

Se stai generando la pagina che collega ai file JS, una semplice soluzione sta aggiungendo il timestamp dell'ultima modifica del file ai collegamenti generati.

Questo è molto simile alla risposta di Huppie, ma funziona nei sistemi di controllo della versione senza sostituzione delle parole chiave. È anche meglio che aggiungere l'ora corrente, poiché ciò impedirebbe la memorizzazione nella cache anche quando il file non è cambiato affatto.


Mi piace questa soluzione, poiché è più facile da mantenere. Se aggiorni un file .js, è tutto ciò che devi fare. Non è necessario aggiornare alcun riferimento al file, poiché il codice aggiungerà automaticamente l'ultimo timestamp aggiornato.
NL3294,

3

La funzione jQuery getScript può anche essere utilizzata per garantire che un file js venga effettivamente caricato ogni volta che viene caricata la pagina.

Ecco come l'ho fatto:

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

Controlla la funzione su http://api.jquery.com/jQuery.getScript/

Per impostazione predefinita, $ .getScript () imposta l'impostazione della cache su false. Ciò aggiunge un parametro di query timestamp all'URL della richiesta per garantire che il browser scarichi lo script ogni volta che viene richiesto.


8
Dobbiamo memorizzare nella cache i file se non si verificano cambiamenti.
Leo Lee,

3

In PHP :

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

In HTML :

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

Come funziona:

In HTML, scrivi il filepathnome e come vuoi, ma solo nella funzione. PHP ottiene il filetimefile e restituisce l' filepath+name+"?"+timeultima modifica


3

Abbiamo creato un SaaS per gli utenti e fornito loro uno script da allegare alla pagina del loro sito Web, e non è stato possibile allegare una versione con lo script poiché l'utente collegherà lo script al loro sito Web per funzionalità e non posso forzarli per cambiare la versione ogni volta che aggiorniamo lo script

Quindi, abbiamo trovato un modo per caricare la versione più recente dello script ogni volta che l'utente chiama lo script originale

il link dello script fornito all'utente

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

il file di 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
}

Spiegazione:

L'utente ha allegato lo script fornito loro nel proprio sito Web e abbiamo verificato che il token univoco associato allo script esiste o non utilizza il selettore jQuery e, in caso contrario, lo carica dinamicamente con un token (o versione) più recente

Questo è chiamare lo stesso script due volte che potrebbe essere un problema di prestazioni, ma risolve davvero il problema di forzare lo script a non caricarsi dalla cache senza mettere la versione nel collegamento di script effettivo fornito all'utente o al client

Disclaimer: non utilizzare se le prestazioni sono un grosso problema nel tuo caso.


2

In asp.net mvc è possibile utilizzare @ DateTime.UtcNow.ToString () per il numero di versione del file js. Il numero di versione cambia automaticamente con la data e si forza il browser dei client ad aggiornare automaticamente il file js. Sto usando questo metodo e questo funziona bene.

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

Come con altre soluzioni suggerite, questo non causerà mai la memorizzazione nella cache del file, il che è generalmente indesiderabile. Finché non sono state apportate modifiche al file, è probabile che il client utilizzi la versione memorizzata nella cache anziché scaricare nuovamente il file invariato ogni volta.
Philip Stratford,

Puoi usare il codice seguente per la tua ragione, file di cache con numero di versione <script src = "~/JsFilePath/JsFile.js?v=@GetAppVersionNumber ()"> </script>
dragonal

2

location.reload (true);

vedi https://www.w3schools.com/jsref/met_loc_reload.asp

Chiamo dinamicamente questa riga di codice per assicurarmi che javascript sia stato recuperato dal server Web anziché dalla cache del browser per evitare questo problema.


L'aggiunta del onload="location.reload();"mio modulo mi consente di ottenere il nuovo JS dopo un aggiornamento invece di riavviare la mia pagina. Questa è una soluzione molto più elegante. Grazie!
ZX9

Grazie, potrei usarlo con un controllo se l'ip è riconosciuto ma non è stato usato per accedere dall'ultimo aggiornamento eseguirlo nella pagina dell'indice dopo il login iniziale degli utenti.
Fi Horan,

onload = "location.reload (true);" Quanto sopra non ha funzionato per me (usando il pallone e la versione corrente di Chrome) anche: w3schools.com/jsref/met_loc_reload.asp
aspiringGuru

1

Una soluzione è aggiungere una stringa di query con un timestamp in essa all'URL durante il recupero della risorsa. Ciò sfrutta il fatto che un browser non memorizzerà nella cache le risorse recuperate dagli URL con stringhe di query.

Tuttavia, probabilmente non vuoi che il browser non memorizzi nella cache queste risorse; è più probabile che tu li desideri nella cache, ma vuoi che il browser recuperi una nuova versione del file quando viene reso disponibile.

La soluzione più comune sembra essere quella di incorporare un timestamp o un numero di revisione nel nome del file stesso. Questo è un po 'più di lavoro, perché il codice deve essere modificato per richiedere i file corretti, ma significa che, ad esempio, la versione 7 del tuo snazzy_javascript_file.js(cioè snazzy_javascript_file_7.js) è memorizzata nella cache del browser fino al rilascio della versione 8, e quindi il tuo codice cambia in prendere snazzy_javascript_file_8.jsinvece.


1

Il vantaggio di utilizzare una file.js?V=1over a fileV1.jsè che non è necessario archiviare più versioni dei file JavaScript sul server.

Il problema che vedo file.js?V=1è che potresti avere codice dipendente in un altro file JavaScript che si interrompe quando si utilizza la nuova versione dei programmi di utilità della libreria.

Per motivi di compatibilità con le versioni precedenti, penso che sia molto meglio utilizzarlo jQuery.1.3.jsper le tue nuove pagine e consentire l'utilizzo delle pagine esistenti jQuery.1.1.js, fino a quando non sei pronto per aggiornare le pagine più vecchie, se necessario.


1

Utilizzare una GETvariabile di versione per impedire la memorizzazione nella cache del browser.

L'aggiunta ?v=AUTO_INCREMENT_VERSIONalla fine dell'URL impedisce la memorizzazione nella cache del browser, evitando tutti gli script memorizzati nella cache.


1

Il mio collega ha appena trovato un riferimento a quel metodo subito dopo aver pubblicato (in riferimento a CSS) su http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/ . Bello vedere che gli altri lo stanno usando e sembra funzionare. Presumo a questo punto che non esiste un modo migliore di trovare-sostituire per incrementare questi "numeri di versione" in tutti i tag di script?



1

Il busting della cache in ASP.NET Core tramite un helper di tag lo gestirà per te e consentirà al tuo browser di conservare gli script / css memorizzati nella cache fino a quando il file non cambia. Aggiungi semplicemente il tag helper asp-append-version = "true" al tag script (js) o link (css):

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

Dave Paquette ha un buon esempio e una spiegazione del busting della cache qui (in fondo alla pagina) Cache Busting


Questo non funziona in ASP.NET normale? Ho provato ad aggiungere la versione asp-append al mio tag script e tutto ciò che il browser vede è il tag script esattamente come appare nell'origine, incluso l'attributo asp-append-version.
Tolsen64,

Questo è un attributo .NET Core associato agli helper di tag. Aggiunge il nome dello script con una versione in modo che il server / browser visualizzi sempre l'ultima versione e i download
ccherwin

0

Soluzione più semplice? Non lasciare affatto la cache del browser. Aggiungi l'ora corrente (in ms) come una query.

(Sei ancora in beta, quindi potresti fare un caso ragionevole per non ottimizzare le prestazioni. Ma qui YMMV.)


13
IMHO questa è una soluzione scadente. Cosa succede se non si è in BETA e si invia un aggiornamento importante?
d -_- b

0

Un modo semplice Modifica 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]

Ciò provoca un reindirizzamento che è dal punto di vista delle prestazioni una soluzione non ottimale, ma funzionante.
volte

0

Di seguito ha funzionato per me:

<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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.