Zauważyłem, że niektóre przeglądarki (w szczególności Firefox i Opera) bardzo gorliwie używają buforowanych kopii plików .css i .js , nawet między sesjami przeglądarki. Prowadzi to do problemu podczas aktualizacji jednego z tych plików, ale przeglądarka użytkownika nadal korzysta z kopii w pamięci podręcznej.
Pytanie brzmi: jaki jest najbardziej elegancki sposób zmuszania przeglądarki użytkownika do ponownego załadowania pliku po jego zmianie?
Idealnie, rozwiązanie nie zmusiłoby przeglądarki do ponownego ładowania pliku przy każdej wizycie na stronie. W odpowiedzi opublikuję własne rozwiązanie, ale jestem ciekawy, czy ktoś ma lepsze rozwiązanie, i pozwolę, aby głosowanie zdecydowało.
Aktualizacja :
Po dłuższej dyskusji tutaj znalazłem przydatną sugestię Johna Millikina i sugestii da5id . Okazuje się, że istnieje na to termin: automatyczne wersjonowanie .
Poniżej zamieściłem nową odpowiedź, będącą połączeniem mojego oryginalnego rozwiązania i sugestii Johna.
Innym pomysłem zasugerowanym przez SCdF byłoby dodanie do pliku fałszywego ciągu zapytania. (Niektóre kody Pythona do automatycznego używania znacznika czasu jako fałszywego ciągu zapytania zostały przesłane przez pi .). Trwa jednak dyskusja, czy przeglądarka buforuje plik z ciągiem zapytania. (Pamiętaj, że chcemy, aby przeglądarka buforowała plik i używała go podczas przyszłych wizyt. Chcemy, aby pobierał plik ponownie tylko po jego zmianie).
Ponieważ nie jest jasne, co dzieje się z fałszywym ciągiem zapytania, nie akceptuję tej odpowiedzi.
ExpiresActive On ExpiresDefault "modification"
.iframe.contentWindow.location.reload(true)
. Zobacz metodę (4) stackoverflow.com/a/22429796/999120 - dotyczy to obrazów, ale to samo dotyczy.Odpowiedzi:
Aktualizacja: Przepisano, aby uwzględnić sugestie Johna Millikina i da5id . To rozwiązanie zostało napisane w języku PHP, ale powinno być łatwe do dostosowania do innych języków.
Aktualizacja 2: Włączanie komentarzy od Nicka Johnsona, że oryginalne
.htaccess
wyrażenie regularne może powodować problemy z takimi plikamijson-1.3.js
. Rozwiązaniem jest przepisanie tylko, jeśli na końcu jest dokładnie 10 cyfr. (Ponieważ 10 cyfr obejmuje wszystkie znaczniki czasu od 9/9/2001 do 11/20/2286.)Najpierw używamy następującej reguły przepisywania w .htaccess:
Teraz piszemy następującą funkcję PHP:
Teraz, gdziekolwiek podasz swój CSS, zmień go z tego:
Do tego:
W ten sposób nigdy nie będziesz musiał ponownie modyfikować tagu łącza, a użytkownik zawsze zobaczy najnowszy CSS. Przeglądarka będzie mogła buforować plik CSS, ale po wprowadzeniu jakichkolwiek zmian w CSS przeglądarka zobaczy to jako nowy adres URL, więc nie będzie używać kopii w pamięci podręcznej.
Może to również działać z obrazami, ulubionymi i JavaScript. Zasadniczo wszystko, co nie jest generowane dynamicznie.
źródło
file_exists
kontrola jest naprawdę konieczna?filemtime
zwróci false w przypadku niepowodzenia, więc dlaczego po prostu nie przypisać wartości zmiennej filemtime do zmiennej i sprawdzić, czy jest fałszywa przed zmianą nazwy pliku? To ograniczyłoby jedną niepotrzebną operację na pliku, która naprawdę by się sumowała.Prosta technika po stronie klienta
Zasadniczo buforowanie jest dobre. Istnieje kilka technik, w zależności od tego, czy rozwiązujesz problem samodzielnie podczas tworzenia witryny, czy też próbujesz kontrolować pamięć podręczną w środowisku produkcyjnym.
Ogólni odwiedzający twoją stronę nie będą mieli takiego samego doświadczenia, jak podczas jej tworzenia. Ponieważ przeciętny użytkownik odwiedza witrynę rzadziej (może tylko kilka razy w miesiącu, chyba że jesteś siecią Google lub hi5), prawdopodobieństwo, że Twoje pliki będą przechowywane w pamięci podręcznej, jest mniejsze. Jeśli chcesz wymusić nową wersję w przeglądarce, zawsze możesz dodać ciąg zapytania do żądania i podnieść numer wersji po dokonaniu poważnych zmian:
Zapewni to, że wszyscy otrzymają nowy plik. Działa, ponieważ przeglądarka sprawdza adres URL pliku, aby ustalić, czy ma on kopię w pamięci podręcznej. Jeśli twój serwer nie jest skonfigurowany do robienia czegokolwiek z ciągiem zapytania, zostanie zignorowany, ale nazwa będzie wyglądać jak nowy plik w przeglądarce.
Z drugiej strony, jeśli tworzysz witrynę internetową, nie chcesz zmieniać numeru wersji za każdym razem, gdy zapisujesz zmianę w wersji programistycznej. To byłoby nudne.
Dlatego podczas tworzenia witryny dobrym pomysłem byłoby automatyczne wygenerowanie parametru ciągu zapytania:
Dodanie ciągu zapytania do żądania jest dobrym sposobem na zaktualizowanie zasobu, ale w przypadku prostej witryny może to być niepotrzebne. I pamiętaj, że buforowanie jest dobrą rzeczą.
Warto również zauważyć, że przeglądarka niekoniecznie skąpa jest w przechowywaniu plików w pamięci podręcznej. Przeglądarki mają zasady dotyczące tego rodzaju rzeczy i zwykle postępują zgodnie z zasadami określonymi w specyfikacji HTTP. Gdy przeglądarka wysyła żądanie do serwera, częścią odpowiedzi jest nagłówek EXPIRES. Data, która informuje przeglądarkę, jak długo powinien być przechowywany w pamięci podręcznej. Następnym razem, gdy przeglądarka napotka żądanie dotyczące tego samego pliku, zobaczy, że ma kopię w pamięci podręcznej, i szuka daty WYGASANIA, aby zdecydować, czy należy go użyć.
Wierzcie lub nie, tak naprawdę to twój serwer sprawia, że pamięć podręczna przeglądarki jest tak trwała. Możesz dostosować ustawienia serwera i zmienić nagłówki EXPIRES, ale ta mała technika, którą napisałem powyżej, jest prawdopodobnie znacznie prostszym sposobem na obejście tego. Ponieważ buforowanie jest dobre, zwykle chcesz ustawić tę datę daleko w przyszłość („Nagłówek dalekiej przyszłości wygasa”) i użyć techniki opisanej powyżej, aby wymusić zmianę.
Jeśli interesują Cię dodatkowe informacje na temat HTTP lub sposób, w jaki te żądania są wysyłane, dobra książka to „Witryny o wysokiej wydajności” Steve'a Soudersa. To bardzo dobre wprowadzenie do tematu.
źródło
<link href='myCss.css?dev=14141'...>
Google mod_pagespeed plugin do apache zrobi automatycznego wersjonowania dla Ciebie. To jest naprawdę śliskie.
Analizuje HTML wychodząc z serwera (działa z PHP, szynami, pythonem, statycznym HTML - czymkolwiek) i przepisuje linki do CSS, JS, plików graficznych, aby zawierały kod identyfikacyjny. Obsługuje pliki pod zmodyfikowanymi adresami URL z bardzo długą kontrolą pamięci podręcznej. Gdy pliki się zmieniają, automatycznie zmienia adresy URL, więc przeglądarka musi je ponownie pobrać. Zasadniczo po prostu działa, bez żadnych zmian w kodzie. To nawet zminimalizuje twój kod przy wyjściu.
źródło
Zamiast ręcznie zmieniać wersję, zalecam użycie skrótu MD5 rzeczywistego pliku CSS.
Twój adres URL byłby więc podobny
Nadal możesz użyć reguły przepisywania w celu usunięcia skrótu, ale zaletą jest to, że teraz możesz ustawić swoją zasadę buforowania na „buforuj na zawsze”, ponieważ jeśli adres URL jest taki sam, oznacza to, że plik pozostaje niezmieniony.
Następnie możesz napisać prosty skrypt powłoki, który obliczy skrót pliku i zaktualizuje tag (prawdopodobnie będziesz chciał przenieść go do osobnego pliku w celu włączenia).
Po prostu uruchom ten skrypt za każdym razem, gdy zmienia się CSS i jesteś dobry. Przeglądarka przeładuje pliki TYLKO po ich zmianie. Jeśli dokonasz edycji, a następnie ją cofniesz, nie będzie problemu z ustaleniem, do której wersji musisz wrócić, aby użytkownicy nie mogli ponownie pobrać.
źródło
Nie jestem pewien, dlaczego wdrażacie to rozwiązanie tak bardzo.
Wystarczy pobrać zmodyfikowany znacznik czasu pliku i dołączyć go do pliku jako kwerendę
W PHP zrobiłbym to jako:
filemtime to funkcja PHP zwracająca zmodyfikowany znacznik czasu pliku.
źródło
mycss.css?1234567890
.<link rel="stylesheet" href="mycss.css?<?php echo filemtime('mycss.css') ?>"/>
, na wypadek, gdyby niektóre argumenty w tym wątku dotyczące buforowania adresów URL za pomocą zmiennych GET (w sugerowanym formacie) były prawidłowe?ver=
więc kto wie!Możesz po prostu umieścić
?foo=1234
na końcu importu css / js, zmieniając 1234 na dowolne. Spójrz na przykład na źródło html SO.Chodzi o to, że? parametry są w każdym razie odrzucane / ignorowane i można zmienić ten numer po uruchomieniu nowej wersji.
Uwaga: Istnieje pewien argument dotyczący tego, jak dokładnie wpływa to na buforowanie. Uważam, że ogólną zasadą jest to, że żądania GET, z parametrami lub bez, powinny być buforowalne, więc powyższe rozwiązanie powinno działać.
Jednak to serwer WWW decyduje, czy chce zastosować się do tej części specyfikacji, i przeglądarki, z której korzysta użytkownik, ponieważ może po prostu iść naprzód i poprosić o nową wersję.
źródło
Słyszałem, że to się nazywa „automatyczne wersjonowanie”. Najczęstszą metodą jest umieszczenie mtime pliku statycznego gdzieś w adresie URL i usunięcie go za pomocą programów do przepisywania lub konfesji adresów URL:
Zobacz też:
źródło
Około 30 istniejących odpowiedzi to świetna rada dla strony internetowej z około 2008 roku. Jeśli jednak chodzi o nowoczesną, jednostronicową aplikację (SPA), nadszedł czas, aby przemyśleć kilka podstawowych założeń… konkretnie pomysł, aby serwer WWW obsługiwał tylko jedną, najnowszą wersję plik.
Wyobraź sobie, że jesteś użytkownikiem, który ma w przeglądarce wersję M SPA załadowaną:
/some.template
/some.template
- czy chcesz zwrócić wersję M lub N szablonu?Jeśli format
/some.template
zmienił się między wersjami M i N (lub nazwa pliku została zmieniona, czy cokolwiek innego) , prawdopodobnie nie chcesz, aby wersja N szablonu była wysyłana do przeglądarki, w której działa stara wersja M analizatora składni . †W aplikacjach internetowych występuje ten problem, gdy spełnione są dwa warunki:
Gdy aplikacja musi obsługiwać wiele wersji równolegle, rozwiązanie buforowania i „przeładowania” staje się trywialne:
/v<release_tag_1>/…files…
,/v<release_tag_2>/…files…
<script>
i<link>
tagi itp., Aby wskazywały ten plik w jednym z wersjonowanych katalogówTen ostatni krok wydaje się trudny, ponieważ może wymagać wywołania narzędzia do tworzenia adresów URL dla każdego adresu URL w kodzie serwera lub klienta. Lub możesz po prostu sprytnie użyć
<base>
tagu i zmienić bieżącą wersję w jednym miejscu.† Jednym ze sposobów jest agresywne zmuszanie przeglądarki do ponownego ładowania wszystkiego po wydaniu nowej wersji. Ale ze względu na zakończenie wszelkich trwających operacji, może być nadal najłatwiej obsługiwać równolegle co najmniej dwie wersje: prąd V i prąd poprzedni.
źródło
base
tagu! Jeśli chodzi o obsługę starego kodu: nie zawsze jest to możliwe, ani nie zawsze jest to dobry pomysł. Nowe wersje kodu mogą obsługiwać przełamywanie zmian w innych częściach aplikacji lub mogą obejmować naprawy awaryjne, łaty w zabezpieczeniach i tak dalej. Sam jeszcze nie wdrożyłem tej strategii, ale zawsze czułem, że ogólna architektura powinna pozwalać wdrożeniom na oznaczanie starej wersji jakoobsolete
i wymuszanie przeładowania przy następnym wywołaniu asynchronicznym (lub po prostu wymuszając cofnięcie autoryzacji wszystkich sesji przez WebSockets ).Nie używaj wersji foo.css? = 1! Przeglądarki nie powinny buforować adresów URL zmiennymi GET. Według http://www.thinkvitamin.com/features/webapps/serving-javascript-fast , choć IE i Firefox to ignorują, Opera i Safari nie! Zamiast tego użyj foo.v1234.css i użyj reguł przepisywania, aby usunąć numer wersji.
źródło
W Laravel (PHP) możemy to zrobić w następujący przejrzysty i elegancki sposób (używając znacznika czasu modyfikacji pliku):
I podobnie w CSS
Przykładowe dane wyjściowe HTML (
filemtime
czas powrotu jako znacznik czasu Unix )źródło
RewriteRule wymaga niewielkiej aktualizacji plików js lub css, które na końcu zawierają wersję z notacją kropkową. Np. Json-1.3.js.
Dodałem klasę negacji kropki [^.] Do wyrażenia regularnego, więc .number. jest ignorowany.
źródło
^(.*)\.[\d]{10}\.(css|js)$ $1.$2
[^.]
tutaj rozwiązujesz . Poza tym pisanie\d
wewnątrz klasy postaci nie ma żadnej korzyści -\d+
zrobi to samo. Jak pisał, Twój wzór zostanie dopasowane dowolną liczbę znaków (łapczywie), a następnie dosłownym kropka, to non-kropka, a następnie jeden-or-więcej cyfr, a następnie kropka, a następniecss
lubjs
, a następnie do końca pliku. Brak odpowiednika na wprowadzenie próbki: regex101.com/r/RPGC62/1W przypadku wersji ASP.NET 4.5 i nowszych można używać grupowania skryptów .
Istnieją inne korzyści związane z pakietowaniem, w tym zwiększona wydajność przy pierwszym ładowaniu strony przy minimalizacji.
źródło
Oto czyste rozwiązanie JavaScript
Powyższe będzie szukać po raz ostatni użytkownik odwiedził twoją stronę. Jeśli ostatnia wizyta miała miejsce przed wydaniem nowego kodu, używa on
location.reload(true)
do wymuszenia odświeżenia strony z serwera.Zwykle mam to jako pierwszy skrypt w ramach,
<head>
więc jest oceniany przed załadowaniem jakiejkolwiek innej treści. Jeśli konieczne jest ponowne załadowanie, użytkownik nie jest prawie zauważalny.Używam pamięci lokalnej do przechowywania znacznika czasu ostatniej wizyty w przeglądarce, ale możesz dodać pliki cookie do miksu, jeśli chcesz obsługiwać starsze wersje IE.
źródło
Ciekawy post. Po przeczytaniu wszystkich odpowiedzi tutaj w połączeniu z faktem, że nigdy nie miałem żadnych problemów z „fałszywymi” ciągami zapytań (co nie jestem pewien, dlaczego wszyscy tak niechętnie korzystają z tego), wydaje mi się, że to rozwiązanie (które eliminuje potrzebę reguł przepisywania apache jak w zaakceptowanej odpowiedzi) polega na obliczeniu krótkiej wartości skrótu zawartości pliku CSS (zamiast godziny danych pliku) jako fałszywego zapytania.
Spowodowałoby to:
Oczywiście rozwiązania datetime również wykonują zadanie w przypadku edycji pliku CSS, ale myślę, że chodzi o zawartość pliku css, a nie o datę pliku, więc po co je pomieszać?
źródło
W moim rozwoju uważam, że chrom ma świetne rozwiązanie.
https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload
Po otwarciu narzędzi programistycznych wystarczy długo kliknąć przycisk odświeżania i puścić po najechaniu myszką na „Opróżnij pamięć podręczną i uruchom ponownie ładowanie”.
To mój najlepszy przyjaciel i jest to bardzo lekki sposób na zdobycie tego, czego chcesz!
źródło
Dzięki w Kip za jego idealne rozwiązanie!
Rozszerzyłem go, aby używał go jako Zend_view_Helper. Ponieważ mój klient wyświetlał swoją stronę na wirtualnym hoście, też ją rozszerzyłem.
Mam nadzieję, że pomoże to również komuś innemu.
Pozdrawiam i dziękuję.
źródło
Nie znalazłem metody DOM po stronie klienta, która dynamicznie tworzy element węzła skryptowego (lub css):
źródło
Google Chrome ma opcję Przeładowania twardego oraz Opróżnij pamięć podręczną i opcję Przeładowania twardego. Możesz kliknąć i przytrzymać przycisk przeładowania (W trybie inspekcji), aby go wybrać.
źródło
ant menu
>More Tools
>Developer Tools
velright click
>Inspect Element
. Jest też ustawienie ukryte gdzieś w narzędziach programistycznych (zapomniałem lokalizacji), aby mocno przeładowywać przy każdym przeładowaniu.Możesz wymusić „buforowanie dla całej sesji”, jeśli dodasz identyfikator sesji jako dokładny parametr pliku js / css:
Jeśli chcesz buforować w całej wersji, możesz dodać kod, aby wydrukować datę pliku lub podobny. Jeśli używasz Javy, możesz użyć niestandardowego tagu, aby wygenerować link w elegancki sposób.
źródło
Załóżmy, że masz plik dostępny w:
możesz albo dołączyć parametr zapytania z informacją o wersji do identyfikatora URI, np .:
lub możesz dodać informacje o wersji, np .:
IMHO druga metoda jest lepsza w przypadku plików CSS, ponieważ mogą one odnosić się do obrazów przy użyciu względnych adresów URL, co oznacza, że jeśli podasz
background-image
podobny parametr:jego adres URL będzie w rzeczywistości:
Oznacza to, że jeśli zaktualizujesz użyty numer wersji, serwer potraktuje to jako nowy zasób i nie użyje wersji buforowanej. Jeśli oprzesz swój numer wersji na Subversion / CVS / etc. Wersja oznacza, że zmiany w obrazach, do których istnieją odniesienia w plikach CSS, zostaną zauważone. Nie jest to zagwarantowane w pierwszym schemacie, tzn. Adres URL w
images/happy.gif
stosunku do/styles/screen.css?v=1235
to/styles/images/happy.gif
, która nie zawiera żadnych informacji o wersji.Zaimplementowałem rozwiązanie buforowania przy użyciu tej techniki z serwletami Java i po prostu obsługuję żądania
/v/*
za pomocą serwletu, który deleguje do zasobu podstawowego (tj/styles/screen.css
.). W trybie rozwoju I ustawić buforowanie nagłówków, które informują klienta, aby zawsze sprawdzić świeżość zasobu z serwera (to zazwyczaj skutkuje 304 jeśli przekazać TomcatDefaultServlet
oraz.css
,.js
itp plik nie uległ zmianie), natomiast w trybie rozmieszczania Ustawiam nagłówki z napisem „cache forever”.źródło
<?php header( 'Location: folder1/login.phtml' ); ?>
.Możesz po prostu dodać losową liczbę z adresem URL CSS / JS jak
źródło
Dla ASP.NET przypuszczam, że następne rozwiązanie z zaawansowanymi opcjami (tryb debugowania / wydania, wersje):
Pliki Js lub Css zawarte w ten sposób:
Global.JsPostfix i Global.CssPostfix jest obliczany w następujący sposób w Global.asax:
źródło
Ostatnio rozwiązałem to za pomocą Pythona. Tutaj kod (powinien być łatwy do dostosowania do innych języków):
Ten kod zasadniczo dołącza znacznik czasu pliku jako parametr zapytania do adresu URL. Wywołanie następującej funkcji
spowoduje
Zaletą jest oczywiście to, że nie musisz już nigdy zmieniać kodu HTML, dotknięcie pliku CSS spowoduje automatyczne unieważnienie pamięci podręcznej. Działa bardzo dobrze, a narzut nie jest zauważalny.
źródło
Jeśli używasz git + PHP, możesz ponownie załadować skrypt z pamięci podręcznej za każdym razem, gdy nastąpi zmiana w repozytorium git, używając następującego kodu:
źródło
Jeśli jesteś programistą, który chce uniknąć buforowania, karta sieci chrom ma opcję wyłączania pamięci podręcznej. W przeciwnym razie możesz to zrobić bez szkieletu renderowania serwera za pomocą dwóch znaczników skryptu.
źródło
To pytanie jest bardzo stare i pojawia się, gdy ktoś przejdzie do tego problemu. To nie jest odpowiedź na pytanie, jak chce tego op, ale odpowiedź dla deweloperów z tym problemem podczas opracowywania i testowania. I nie mogę opublikować nowego pytania na ten temat, ponieważ zostanie oznaczony jako duplikat.
Podobnie jak wiele innych, chciałem tylko na krótko usunąć buforowanie.
"keep caching consistent with the file"
.. jego sposób jest zbyt trudnyOgólnie rzecz biorąc, nie mam nic przeciwko ładowaniu więcej - nawet ładowaniu plików, które nie uległy zmianie - w większości projektów - jest praktycznie nieistotne. Podczas opracowywania aplikacji - przeważnie ładujemy z dysku,
localhost:port
więc - więc tenincrease in network traffic
problem nie stanowi problemu zerwania umowy .Większość małych projektów po prostu się bawi - nigdy nie trafiają do produkcji. więc dla nich nie potrzebujesz nic więcej ...
Jeśli korzystasz z Narzędzi Chrome dla programistów , możesz postępować zgodnie z tą metodą wyłączania buforowania, jak na obrazku poniżej:
A jeśli masz problemy z buforowaniem przeglądarki Firefox :
Zrób to tylko w fazie rozwoju, potrzebujesz również mechanizmu wymuszającego ponowne załadowanie do produkcji, ponieważ użytkownicy będą używać starych modułów unieważnionych w pamięci podręcznej, jeśli często aktualizujesz aplikację i nie zapewnisz dedykowanego mechanizmu synchronizacji pamięci podręcznej, takiego jak te opisane w odpowiedziach powyżej.
Tak, te informacje są już w poprzednich odpowiedziach, ale wciąż muszę przeprowadzić wyszukiwanie w Google, aby je znaleźć.
Mam nadzieję, że ta odpowiedź jest bardzo jasna i teraz nie musisz.
źródło
Wydaje się, że wszystkie odpowiedzi tutaj sugerują jakąś wersjonowanie w schemacie nazewnictwa, który ma swoje wady.
Przeglądarki powinny zdawać sobie sprawę z tego, co buforować, a czego nie buforować, czytając odpowiedź serwera WWW, w szczególności nagłówki http - na jak długo ten zasób jest ważny? czy ten zasób został zaktualizowany od czasu jego ostatniego pobrania? etcetera.
Jeśli wszystko jest skonfigurowane „poprawnie”, po prostu aktualizacja plików aplikacji powinna (w pewnym momencie) odświeżyć pamięć podręczną przeglądarki. Możesz na przykład skonfigurować serwer WWW tak, aby przeglądarka nigdy nie buforowała plików (co jest złym pomysłem).
Bardziej szczegółowe wyjaśnienie tego, jak to działa, znajduje się tutaj https://www.mnot.net/cache_docs/#WORK
źródło
Po prostu dodaj ten kod, w którym chcesz dokonać twardego przeładowania (wymuś, aby przeglądarka przeładowała buforowane pliki CSS / JS). Zrób to wewnątrz .load, aby nie odświeżył się jak pętla
źródło
Wystarczy użyć kodu po stronie serwera, aby dodać datę pliku ... w ten sposób BĘDZIE on buforowany i ponownie załadowany, gdy plik się zmieni
W ASP.NET
Można to uprościć:
Dodając metodę rozszerzenia do projektu w celu rozszerzenia strony:
źródło
Sugeruję wdrożenie następującego procesu:
wersja plików css / js przy każdym wdrożeniu, na przykład: screen.1233.css (liczba może być wersją SVN, jeśli używasz systemu kontroli wersji)
zminimalizuj je, aby zoptymalizować czas ładowania
źródło