Radzenie sobie z pamięcią podręczną przeglądarki w aplikacjach jednostronicowych

27

Próbuję wymyślić, jak prawidłowo obsługiwać pamięć podręczną przeglądarki internetowej dla aplikacji jednostronicowych.

Mam dość typowy projekt: kilka plików HTML, JS i CSS implementujących SPA oraz garść danych JSON zużywanych przez SPA. Problemy pojawiają się, gdy chcę przekazać aktualizację: aktualizuję statyczną część witryny i kod, który generuje JSON w tym samym czasie, ale przeglądarki klienckie często mają buforowaną część statyczną, więc stary kod próbuje przetworzyć nowe dane i może (w zależności od dokonanych zmian) napotkać problemy. (W szczególności IE wydaje się bardziej agresywny niż Chrome lub Firefox w kwestii używania JS w pamięci podręcznej bez ponownego sprawdzania poprawności).

Jak najlepiej sobie z tym poradzić?

  1. Upewnij się, że moje zmiany JSON są zgodne wstecz i zakładam, że pamięci podręczne przeglądarki wygasną w rozsądnym czasie.
  2. Osadź jakiś numer wersji zarówno w statycznym JS, jak i JSON, a następnie uruchom, window.location.reload(true);jeśli się nie zgadzają.
  3. Wymyśl odpowiednią kombinację nagłówków ( must-revalidatelub no-cachecokolwiek innego; źródła różnią się w jaki sposób to zrobić), aby zapewnić, że przeglądarki zawsze sprawdzają poprawność wszystkich zasobów przy każdym załadowaniu, nawet jeśli oznacza to kilka dodatkowych podróży w obie strony, aby załadować witrynę.
  4. Mikro zarządzaj moją kontrolą pamięci podręcznej i wygasaj nagłówki, aby zawartość statyczna wygasała, gdy chcę przekazać aktualizację.
  5. Coś innego?
Josh Kelley
źródło
1
Słyszałem, że numery 3 i 4 niespodziewanie zawodzą we wbudowanych kontrolkach przeglądarki, jeśli twoje środowisko jest złe ( kaszel iOS) od współpracowników. # 1 i # 2 mogą być wyborem na poziomie aplikacji, ale nadal mogą (?) Powodować problemy z pamięcią podręczną dla innych zasobów lub częściowego ładowania zasobów. Jedyną rzeczą, którą widziałem niezawodnie działającą w kodzie gotowym do produkcji, jest pobieranie yoururl.html? <SomeTimeStamp>, ponieważ spowoduje to usunięcie większości mechanizmów buforowania. Premia: zwiń całą aplikację internetową do pliku, aby ładowanie zakończyło się sukcesem lub niepowodzeniem. Wada: działa najlepiej na link lokalny. Twój przebieg może się różnić. Powodzenia!
J Trana,
2
+1 do używania numeru wersji lub znacznika czasu jako parametru adresu URL zasobów.
9000

Odpowiedzi:

14

Potrzebujesz rozwiązania pomijania pamięci podręcznej . Rolą pomijania pamięci podręcznej jest:

  1. Zmień nazwę zasobów na unikalną nazwę w zależności od ich zawartości.
  2. Zaktualizuj wszystkie odniesienia do tych zasobów.

W projekcie opartym na Grunt często używa się grunt-rev, aby zapewnić, że wszystkie pliki, które wymagają odświeżenia, mają unikalne nazwy, oparte na ich zawartości.

Jeśli upewnisz się, że twoje pliki JSON otrzymają nazwy plików w pamięci podręcznej wraz z odniesieniami do nich w JavaScript, klienci zawsze będą ładować pliki JSON, których oczekuje Javascript.

Zaletą nazewnictwa plików opartych na haszowaniu jest to, że pliki, które nie uległy zmianie, otrzymają te same nazwy plików po pomijaniu pamięci podręcznej, dzięki czemu przeglądarki mogą bezpiecznie używać zawartości pamięci podręcznej, jeśli nie uległy zmianie.

Oczywiście jest to coś, co chcesz zautomatyzować w ramach kompilacji produkcyjnej projektu, więc nie musisz ręcznie śledzić zmiany nazw plików i odniesień.

Ted Percival
źródło
2
+1 za kursywę „pomijanie pamięci podręcznej”, która otwiera drzwi do produktywnego wyszukiwania w Google tych rzeczy.
Zak Kus,
@Ted Percival - framework Yeoman robi to, z czego korzystam, ale widzę problem. kiedy wypuszczam nową wersję, przeglądarka może mieć buforowany plik index.html z odniesieniami do starych plików ... a przeglądarka wyświetla błąd. jak mam to naprawić? (A.) dowiązanie symboliczne wszystkich starych nazw plików do nowych (to działa) (B.) dodaj nagłówek bez pamięci podręcznej do index.html (ale czy to zawsze jest przestrzegane) (C.) dodaj .htaccess, aby rozpoznać poprawiony plik i wyszukaj podstawowy (tj. 12345.main.js -> main.js)
timh
5

Możesz użyć if-modified-since + last-modifiedlub if-none-match + etagnagłówków wraz z odpowiednim cache-controlnagłówkiem. (Mogą występować błędy przeglądarki , ale w najnowszych przeglądarkach nie można nic zrobić).

Jeśli pliki są statyczne, sugeruję użycie if-modified-since, ponieważ można to zrobić automatycznie przy dobrze skonfigurowanym serwerze HTTP. Powinien odesłać 304, jeśli plik nie został zmodyfikowany od ostatniego pobrania.

Nie sądzę, aby twoje # 1 i # 2 działałyby długoterminowo. # 3 lub # 4 mogą działać. # 3 jest prostszy, ale musisz nauczyć się radzić sobie z tym problemem tylko raz. Więc gdybym był tobą, wypróbowałbym numer 4, ale rozwiązanie może zależeć od przeglądarki używanej przez twoich klientów ... Na przykład IE8 ma problemy z aktualizacją pamięci podręcznej ajax itp.

inf3rno
źródło
2

Jeśli możesz dołączyć Java Servlet Filter do swojego SPA, oto działające rozwiązanie: CorrectBrowserCacheHandlerFilter.java

Zasadniczo, gdy przeglądarka żąda plików statycznych, serwer przekieruje każde żądanie do tego samego, ale z parametrem zapytania mieszającego ( ?v=azErTna przykład), który zależy od zawartości docelowego pliku statycznego.

W ten sposób przeglądarka nigdy nie buforuje plików statycznych zadeklarowanych index.htmlna przykład w twoim (ponieważ zawsze otrzyma a 302 Moved Temporarily), ale buforuje tylko te z wersją skrótu (serwer za nie odpowie 200). Pamięć podręczna przeglądarki będzie efektywnie wykorzystywana w przypadku plików statycznych z wersją skrótu.

Uwaga: Jestem autorem CorrectBrowserCacheHandlerFilter.java.

Anthony O.
źródło