Caching-stijlen. Best practices voor cachen. Hoe werkt Cache-Control?

HTML5 maakt het mogelijk om webapplicaties te maken die zelfs zonder internetverbinding werken.

Verbeterde paginacaching

Let op: IE10+, Chrome, Firefox, Opera en Safari ondersteunen deze technologie.

HTML5 verbetert de cachemogelijkheden van browsers. Nu kunnen webpagina's volledig toegankelijk zijn voor gebruikers, zelfs zonder internetverbinding.

Het gebruik van HTML5-caching biedt de volgende voordelen:

  • Hiermee kunnen gebruikers webpagina's bekijken, zelfs zonder internetverbinding.
  • Verhoogde laadsnelheid van pagina's - pagina's worden lokaal op de computer van de gebruiker opgeslagen en zullen daarom veel sneller laden.
  • Verminderde serverbelasting - de server hoeft sommige gebruikersverzoeken niet te verwerken.
Voorbeeld van het gebruik van HTML5-caching

...Documentinhoud...

HTML5-caching declareren

Om het cachingmechanisme op uw webpagina's te gebruiken, moet u het manifest-attribuut aan de tag toevoegen en als waarde het pad opgeven naar een speciaal bestand waarin caching-parameters worden gedeclareerd.

Als dit kenmerk niet is ingesteld op een webpagina en de link ernaartoe niet in het cachebestand staat, wordt de pagina niet in de cache opgeslagen.

Het cachebestand kan elke extensie hebben (bijvoorbeeld.appcache of.mf), maar moet een speciaal MIME-type hebben: "text/cache-manifest".

In sommige gevallen heeft de webserver mogelijk aanvullende configuratie nodig om een ​​bepaald MIME-type te kunnen bedienen. Om bijvoorbeeld de Apache-webserver te configureren, moet u de volgende code toevoegen aan het .htaccess-bestand:

AddType tekst/cache-manifest .appcache

Inhoud van het cachebestand

Een cachebestand is een tekstbestand dat de browser vertelt welke bestanden in de cache moeten worden opgeslagen.

Het bestand kan drie secties bevatten:

  • CACHE MANIFEST - deze sectie specificeert links naar bestanden die in de cache moeten worden opgeslagen. De browser zal alle vermelde bestanden automatisch in de cache opslaan onmiddellijk na de eerste download.
  • NETWERK - deze sectie specificeert bestanden waarvoor een permanente internetverbinding vereist is. De browser slaat de bestanden die in deze sectie worden vermeld niet in de cache op.
  • FALLBACK - als de in deze sectie gespecificeerde bestanden om welke reden dan ook niet beschikbaar zijn, worden gebruikers automatisch doorgestuurd naar een ander gespecificeerd bestand.

De sectie CACHE MANIFEST moet aanwezig zijn in alle cachebestanden. De secties NETWORK en FALLBACK ontbreken mogelijk.

Voorbeeld cachebestand:

CACHE MANIFEST #Deze sectie vermeldt de bestanden die in de cache worden opgeslagen index.html flower.png NETWERK #Deze sectie vermeldt de bestanden waarvoor een internetverbinding nodig is login-pagina.php FALLBACK #Als mob.html niet beschikbaar is, wordt de gebruiker doorgestuurd naar offline.html /mob .html /offline.html #Als een van de HTML-bestanden niet beschikbaar is, wordt de gebruiker doorgestuurd naar offline.html *.html /offline.html

Let op: een webpagina die naar een cachebestand linkt, wordt automatisch in de cache opgeslagen. Het opnemen ervan in het cachebestand zelf is dus optioneel, maar toch aanbevolen.

Let op: sommige browsers hebben mogelijk een limiet voor de grootte van de in de cache opgeslagen inhoud op één site.

Gecachte bestanden bijwerken

Zodra de bestanden in de cache zijn opgeslagen, blijft de browser de in de cache opgeslagen versie ervan keer op keer weergeven, zelfs als u de inhoud van deze bestanden op de server wijzigt.

Om inhoud in de cache bij te werken, moet u een van de volgende handelingen uitvoeren:

  • Wis de cache in de browser van de gebruiker
  • Update de inhoud van het cachebestand
  • Browsercache programmatisch vernieuwen (met behulp van JavaScript)

Om de inhoud van een bestand bij te werken, kunt u de volgende truc gebruiken: in plaats van de inhoud van het bestand rechtstreeks bij te werken, kunt u er een commentaar aan toevoegen met de wijzigingsdatum en/of de versie van het bestand en in de verander in de toekomst alleen de inhoud van deze opmerking wanneer u de inhoud in de cache wilt vernieuwen.

Veel mensen denken dat CSS-bestanden die via link of @import zijn verbonden standaard niet in de cache worden opgeslagen. Ik moet je teleurstellen. Het is de CSS die in een apart bestand wordt geplaatst dat in de cache wordt opgeslagen, en heel goed, ik zou zeggen uitstekend. Deze informatie is betrouwbaar geverifieerd in zowel 6 en hoger als andere browsers. Het is de moeite waard om op te merken dat veel mensen dergelijke bestanden met een enorme snelheid in de cache opslaan, om zo te zeggen dat ze hiervoor de eerste plaats behalen. Overigens is het in veel gevallen dit mechanisme waarmee Opera een aanzienlijke snelheid heeft in vergelijking met andere browsers. Maar ik maak meteen een voorbehoud dat het juist deze ‘super’ caching in Opera is die er een wrede grap mee uithaalt bij het gebruik van AJAX-technologie. Terwijl anderen veel veranderingen aanbrengen bij het gebruik van AJAX, neemt Opera de oude. Maar dit is een nummer over een apart onderwerp.

CSS-caching

MAAR! Toch hebben sommige mensen problemen in deze richting. Dit komt meestal door een verkeerd geconfigureerde Apache-server, die niet geheel correcte headers produceert. En met behulp van de header kunt u het cachen van bestanden beheren. Standaard is de cache uiteraard altijd ingeschakeld. Maar er zijn momenten waarop het niet nodig is om bestanden in de cache op te slaan. Om deze reden beginnen zelfs de professionals te dansen met tamboerijnen met betrekking tot HTTP-headers. Maar als je dit hele artikel leest, ben je nog ver verwijderd van het beheren van HTTP-headers. Ik verzeker u dat u in de nabije toekomst niet met een dergelijk probleem zult worden geconfronteerd. En toch, als je tot de kern nieuwsgierig bent, dan zal ik je kort vertellen hoe dit gebeurt.

  • stuurt een HTTP-header naar de WEB-server - ze zeggen: luister, paprika, geef me een CSS-bestand, anders heb ik CSS, maar de laatste tijd zijn er dergelijke veranderingen geweest.
  • En de server zegt tegen hem: schat, er zijn sinds dat moment geen veranderingen meer geweest, gebruik gerust je oude CSS.
  • Als de CSS is gewijzigd, werkt de browser domweg de CSS in zijn cache bij.
  • Nou, als ik niet moe ben, dan een beetje wetenschappelijke onzin van een soort experiment.

    Ik zeg meteen dat de onderste tekst slecht zal worden begrepen door nieuwkomers op WEB. Dit zal vooral nuttig zijn voor degenen die worden geconfronteerd met de taak om de cache in en uit te schakelen.

    Alle experimenten werden uitgevoerd op een echt, betaald exemplaar. Een goede hoster, om zo te zeggen, waarmee je de structuur van HTTP-headers kunt wijzigen zonder paranoïde te zijn dat deze wordt gehackt op basis van de HTTP-header :)

    Browsermodi

    Elke browser heeft dus 2 modi:

    1. Standaardmodus, retourkop:

    Cache-Control: geen opslag, geen cache, moet opnieuw valideren, post-check=0, pre-check=0

    2. Modus met caching ingeschakeld, header geretourneerd:

    Cache-Control: privé, max. leeftijd=10800, pre-check=10800

    Vervolgens beschrijf ik het gedrag van browsers FireFox 3.5 en hoger

    In de eerste modus worden externe JavaScript-bestanden stevig in de cache opgeslagen en wordt er niet eens gecontroleerd op updates, tenzij de pagina gedwongen wordt te vernieuwen. De CSS wordt gecontroleerd door het headerverzoek.

    If-Modified-Since: "huidige datum" GMT If-None-Match: "aangepaste hashcode"

    Dat wil zeggen dat de CSS alleen opnieuw wordt geladen als deze daadwerkelijk is bijgewerkt.

    Ten tweede stopt de tweede modus met het helemaal bijwerken van de pagina. Dat wil zeggen, zelfs als we de inhoud hebben gewijzigd die op de pagina in de database wordt weergegeven, wordt dit niet weergegeven, zelfs niet als we de update forceren, omdat er een verzoek wordt verzonden:

    GET / HTTP/1.1 Host: xxx.com If-Modified-Since: huidige datum GMT

    en krijgt het antwoord:

    HTTP/1.1 304 Niet gewijzigd

    Internet Explorer 8 (IE8)

    In de eerste modus verzendt Internet Explorer If-Modified-Since & If-None-Match-verzoeken voor zowel JavaScript als CSS, dat wil zeggen dat JavaScript en CSS alleen worden geladen als deze daadwerkelijk zijn bijgewerkt. Hetzelfde gebeurt als u een paginavernieuwing forceert.

    In de tweede modus verzendt Internet Explorer ook If-Modified-Since & If-None-Match-verzoeken voor zowel JavaScript als CSS. Maar tegelijkertijd probeert het niet eens de pagina zelf te laden/bij te werken, dat wil zeggen, het verzendt niet eens een verzoek, dat wil zeggen dat uw js/css wordt bijgewerkt, maar de sjabloon en pagina-inhoud niet. Zelfs een geforceerde paginavernieuwing helpt niet om de inhoud bij te werken.

    Opera 10 en ouder

    In de eerste modus van Opera, in de eerste modus, hangt het updaten van js & CSS af van de waarde waarop de optie Afbeeldingen controleren is ingesteld in de instellingen. Als de optie is ingesteld op Altijd, verzendt Opera verzoeken met If-Modified-Since & If-None-Match om te controleren op js- en css-updates. Als de waarde bijvoorbeeld op 5 uur is ingesteld, wordt deze dienovereenkomstig elke 5 uur gecontroleerd, of door de pagina geforceerd te vernieuwen.

    Ten tweede controleert Opera de js & CSS-update niet (maakt geen GET-verzoeken) en doet ook geen GET-verzoek aan de pagina zelf, dat wil zeggen dat we noch de js & css-update noch de inhoudsupdate zullen zien, zoals in andere gevallen en in andere browsers. Maar met een gedwongen update is Opera beter. In tegenstelling tot IE & FF vraagt ​​Opera expliciet om de pagina-inhoud zonder If-Modified-Since & If-None-Match. Verzoeken om js & CSS bij te werken tijdens een geforceerde update worden al geleverd met If-Modified-Since & If-None-Match.

    Conclusies
  • Caching is, tenzij je precies begrijpt hoe het in verschillende browsers werkt en wat de gevolgen zijn, nogal gevaarlijk.
  • Caching kan alleen worden ingeschakeld als de pagina niet vaak wordt bijgewerkt (dat wil zeggen als de site geen pagina's heeft die in realtime worden bijgewerkt) en zelfs in dit geval is het noodzakelijk om een ​​limiet in te stellen voor de caching-beperkingsperiode (bijvoorbeeld , enkele uren of een dag)
  • FireFox gedraagt ​​zich naar mijn mening iets slimmer dan IE, omdat het zelfs als caching uitgeschakeld is niet voortdurend controleert op JavaScript-updates, wat logisch lijkt, omdat JavaScript zeer zelden wordt bijgewerkt.
  • Met Opera kunt u het bijwerken van afbeeldingen, JavaScript en CSS flexibel beheren met behulp van de instelling Afbeeldingen controleren, wat een pluspunt is. Opera gedraagt ​​zich ook beter dan IE & FF als caching en geforceerde updates zijn ingeschakeld, omdat, laat me je eraan herinneren, Opera in dit geval de inhoud van de pagina volledig bijwerkt, en IE & FF zullen je zalig onbewust achterlaten.
  • Veel succes voor u en winstgevende sites.

    Een goed geconfigureerde caching levert enorme prestatievoordelen op, bespaart bandbreedte en verlaagt de serverkosten, maar veel sites implementeren caching slecht, waardoor een race condition ontstaat die ervoor zorgt dat onderling verbonden bronnen niet meer synchroon lopen.

    De overgrote meerderheid van de best practices voor caching vallen in een van de volgende twee patronen:

    Patroon nr. 1: onveranderlijke inhoud en lange max-age cache Cache-Control: max-age=31536000
    • De inhoud van de URL verandert daarom niet...
    • De browser of CDN kan de bron eenvoudig een jaar lang in de cache opslaan
    • Gecachte inhoud die jonger is dan de opgegeven maximale leeftijd kan worden gebruikt zonder de server te raadplegen

    Pagina: Hé, ik heb "/script-v1.js", "/styles-v1.css" en "/cats-v1.jpg" nodig 10:24

    Cash: Ik ben leeg, hoe zit het met jou, Server? 10:24

    Server: Oké, hier zijn ze. Trouwens, Cash, ze mogen een jaar lang worden gebruikt, niet langer. 10:25

    Contant: bedankt! 10:25

    Pagina: Hoera! 10:25

    Volgende dag

    Pagina: Hé, ik heb "/script-v2 .js", "/styles-v2 .css" en "/cats-v1.jpg" nodig 08:14

    Contant geld: er is een foto met katten, maar niet de rest. Server? 08:14

    Server: Eenvoudig - hier is de nieuwe CSS & JS. Nogmaals, Cash: hun houdbaarheid is niet meer dan een jaar. 08:15

    Contant geld: geweldig! 08:15

    Pagina: Bedankt! 08:15

    Contant geld: Hmm, ik heb "/script-v1.js" & "/styles-v1.css" al een tijdje niet meer gebruikt. Het is tijd om ze te verwijderen. 12:32

    Met dit patroon verander je nooit de inhoud van een specifieke URL, maar verander je de URL zelf:

    Elke URL heeft iets dat samen met de inhoud verandert. Dit kan een versienummer zijn, een wijzigingsdatum of een inhoudshash (wat ik voor mijn blog heb gekozen).

    De meeste server-side frameworks hebben tools waarmee je dit soort dingen gemakkelijk kunt doen (in Django gebruik ik Manifest​Static​Files​Storage); Er zijn ook hele kleine bibliotheken in Node.js die dezelfde problemen oplossen, bijvoorbeeld gulp-rev.

    Dit patroon is echter niet geschikt voor zaken als artikelen en blogposts. Hun URL's kunnen niet worden geversieerd en hun inhoud kan veranderen. Serieus, ik heb vaak grammaticale en interpunctiefouten en moet de inhoud snel kunnen bijwerken.

    Patroon #2: veranderlijke inhoud die altijd wordt gevalideerd op de server Cache-Control: geen cache
    • De inhoud van de URL verandert, wat betekent...
    • Elke lokaal in de cache opgeslagen versie kan niet worden gebruikt zonder de server op te geven.

    Pagina: Hé, ik heb de inhoud nodig van "/about/" en "/sw.js" 11:32

    Contant geld: Ik kan je niet helpen. Server? 11:32

    Server: Er zijn er enkele. Contant geld, houd ze bij je, maar vraag het me voordat je ze gebruikt. 11:33

    Contant: precies! 11:33

    Pagina: Bedankt! 11:33

    De volgende dag

    Pagina: Hé, ik heb de inhoud van "/about/" en "/sw.js" opnieuw nodig 09:46

    Contant geld: Een minuutje. Server, zijn mijn kopieën in orde? De kopie van "/about/" is van maandag en "/sw.js" is van gisteren. 09:46

    Server: "/sw.js" is niet veranderd... 09:47

    Contant geld: cool. Pagina, behoud "/sw.js" . 09:47

    Server: ...maar “/about/” Ik heb een nieuwe versie. Contant geld, houd het vast, maar vergeet niet, net als de vorige keer, het mij eerst te vragen. 09:47

    Contant geld: snap het! 09:47

    Pagina: Geweldig! 09:47

    Let op: no-cache betekent niet “niet cachen”, het betekent “controleren” (of opnieuw valideren) van de in de cache opgeslagen bron op de server. En no-store vertelt de browser dat hij helemaal geen cache mag gebruiken. Bovendien betekent must-revalidate niet dat er sprake is van verplichte hervalidatie, maar dat de in de cache opgeslagen bron alleen wordt gebruikt als deze jonger is dan de opgegeven max-age , en alleen anders wordt deze opnieuw gevalideerd. Dit is hoe alles begint met het cachen van trefwoorden.

    In dit patroon kunnen we een ETag (versie-ID naar keuze) of een Last-Modified-header aan het antwoord toevoegen. De volgende keer dat de client om inhoud vraagt, wordt respectievelijk een If-None-Match of If-Modified-Since uitgevoerd, waardoor de server kan zeggen: "Gebruik wat je hebt, je cache is up-to-date", d.w.z. HTTP 304 retourneren.

    Als het verzenden van ETag / Last-Modified niet mogelijk is, verzendt de server altijd de volledige inhoud.

    Dit patroon vereist altijd netwerkoproepen, dus het is niet zo goed als het eerste patroon, dat zonder netwerkverzoeken kan.

    Het is niet ongebruikelijk dat we niet over de infrastructuur beschikken voor het eerste patroon, maar er kunnen ook problemen optreden met netwerkverzoeken in patroon 2. Als gevolg hiervan wordt een tussenliggende optie gebruikt: korte maximale leeftijd en veranderlijke inhoud. Dit is een slecht compromis.

    Het gebruik van max-age met veranderlijke inhoud is over het algemeen de verkeerde keuze

    En helaas is het gebruikelijk; Github-pagina's zijn een voorbeeld.

    Voorstellen:

    • /artikel/
    • /stijlen.css
    • /script.js

    Met serverheader:

    Cache-Control: moet opnieuw valideren, max-leeftijd=600

    • URL-inhoud verandert
    • Als de browser een cacheversie heeft die recenter is dan 10 minuten, wordt deze gebruikt zonder de server te raadplegen
    • Als een dergelijke cache niet aanwezig is, wordt een netwerkverzoek gebruikt, indien mogelijk met If-Modified-Since of If-None-Match

    Pagina: Hé, ik heb "/article/", "/script.js" en "/styles.css" nodig 10:21

    Cash: Ik heb niets zoals jij, Server? 10:21

    Server: Geen probleem, hier zijn ze. Maar onthoud: contant geld: ze kunnen binnen 10 minuten worden gebruikt. 10:22

    Contant geld: Ja! 10:22

    Pagina: Bedankt! 10:22

    Pagina: Hé, ik heb "/article/", "/script.js" en "/styles.css" opnieuw nodig 10:28

    Cash: Oeps, het spijt me, maar ik ben "/styles.css" kwijtgeraakt, maar ik heb al het andere, alsjeblieft. Server, kunt u "/styles.css" voor mij aanpassen? 10:28

    Server: Makkelijk, hij is al veranderd sinds de laatste keer dat je hem meenam. Je kunt het de komende 10 minuten veilig gebruiken. 10:29

    Contant: geen probleem. 10:29

    Pagina: Bedankt! Maar het lijkt erop dat er iets mis is gegaan! Alles is kapot! Wat is er precies aan de hand? 10:29

    Dit patroon heeft recht op leven tijdens het testen, maar het breekt alles in een echt project en is erg moeilijk te volgen. In het bovenstaande voorbeeld heeft de server de HTML, CSS en JS bijgewerkt, maar de pagina wordt weergegeven met de oude in de cache opgeslagen HTML en JS, plus de bijgewerkte CSS van de server. Niet-overeenkomende versies verpesten alles.

    Wanneer we belangrijke wijzigingen in HTML aanbrengen, veranderen we vaak zowel de CSS om de nieuwe structuur goed weer te geven, als het JavaScript om de inhoud en stijl bij te houden. Al deze bronnen zijn onafhankelijk, maar caching-headers kunnen dit niet uitdrukken. Als gevolg hiervan kunnen gebruikers eindigen met de nieuwste versie van een of twee bronnen en de oude versie van de rest.

    max-age wordt ingesteld ten opzichte van de responstijd, dus als alle bronnen worden overgedragen als onderdeel van één enkel adres, verlopen ze tegelijkertijd, maar is er nog steeds een kleine kans op desynchronisatie. Als u pagina's heeft die geen JavaScript bevatten of andere stijlen bevatten, zijn de vervaldata van de cache niet gesynchroniseerd. En erger nog, de browser haalt voortdurend inhoud uit de cache, niet wetende dat HTML, CSS en JS onderling afhankelijk zijn, zodat hij met plezier één ding uit de lijst kan halen en al het andere kan vergeten. Als u al deze factoren samen in overweging neemt, moet u begrijpen dat de kans op niet-overeenkomende versies vrij groot is.

    Voor de gebruiker kan het resultaat een kapotte pagina-indeling of andere problemen zijn. Van kleine foutjes tot totaal onbruikbare inhoud.

    Gelukkig hebben gebruikers een nooduitgang...

    Soms helpt het verversen van de pagina

    Als de pagina wordt geladen door vernieuwen, voeren browsers altijd een hervalidatie aan de serverzijde uit, waarbij max-age wordt genegeerd. Daarom, als de gebruiker iets kapot heeft vanwege max-age , kan een eenvoudige paginavernieuwing alles repareren. Maar nadat de lepels zijn gevonden, zal er natuurlijk nog steeds sediment achterblijven en zal de houding ten opzichte van uw site enigszins anders zijn.

    Een servicemedewerker kan de levensduur van deze bugs verlengen

    U hebt bijvoorbeeld een servicemedewerker als deze:

    Const-versie = "2"; self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => cache.addAll([ "/styles.css", "/script .js" ]))); )); self.addEventListener("activate", event => ( // ...verwijder oude caches... )); self.addEventListener("fetch", event => ( event.respondWith(caches.match(event.request) .then(response => respons || fetch(event.request))); ));

    Deze servicemedewerker:

    • cachet script en stijlen
    • gebruikt cache als er een match is, anders heeft hij toegang tot het netwerk

    Als we de CSS/JS wijzigen, verhogen we ook het versienummer, wat een update activeert. Omdat addAll echter eerst toegang heeft tot de cache, kunnen we in een raceconditie terechtkomen vanwege de maximale leeftijd en niet-overeenkomende CSS- en JS-versies.

    Zodra ze in de cache zijn opgeslagen, hebben we incompatibele CSS en JS tot de volgende update van de servicemedewerker - en dat is tenzij we tijdens de update opnieuw in een raceconditie terechtkomen.

    U kunt caching overslaan in de service worker:

    Self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => cache.addAll([ new Request("/styles.css", ( cache: "no-cache" )), new Request("/script.js", ( cache: "no-cache" )) ])));

    Helaas worden opties voor caching niet ondersteund in Chrome/Opera en zijn ze zojuist toegevoegd aan de nachtelijke build van Firefox, maar je kunt het zelf doen:

    Self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => Promise.all([ "/styles.css", "/script .js" ].map(url => ( // cache-bust met behulp van een willekeurige querystring return fetch(`$(url)?$(Math.random())`).then(response => ( // fail op 404, 500 etc if (!response.ok) throw Error("Niet ok"); return cache.put(url, response )) ))));

    In dit voorbeeld reset ik de cache met een willekeurig getal, maar je kunt verder gaan en een hash van de inhoud toevoegen tijdens het bouwen (dit is vergelijkbaar met wat sw-precache doet). Dit is een soort implementatie van het eerste patroon met behulp van JavaScript, maar werkt alleen met de servicemedewerker, niet met browsers en CDN.

    Servicemedewerkers en HTTP-cache werken prima samen, laat ze niet vechten!

    Zoals u kunt zien, kunt u de caching-bugs in uw servicemedewerker omzeilen, maar het is beter om de oorzaak van het probleem op te lossen. Het correct instellen van caching maakt niet alleen het werk van de servicemedewerker eenvoudiger, maar helpt ook browsers die servicemedewerkers niet ondersteunen (Safari, IE/Edge) en stelt je ook in staat het maximale uit je CDN te halen.

    Goede caching-headers kunnen het updaten van een servicemedewerker ook veel eenvoudiger maken.

    Const-versie = "23"; self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => cache.addAll([ "/", "/script-f93bca2c. js", "/styles-a837cb1e.css", "/cats-0e9a2ef4.jpg" ]))); ));

    Hier heb ik de hoofdpagina met patroon #2 (hervalidatie aan de serverzijde) en alle andere bronnen met patroon #1 (onveranderlijke inhoud) in de cache opgeslagen. Elke update van een servicemedewerker veroorzaakt een verzoek naar de hoofdpagina en alle andere bronnen worden alleen geladen als hun URL is gewijzigd. Dit is goed omdat het verkeer bespaart en de prestaties verbetert, ongeacht of u een upgrade uitvoert van een vorige of zeer oude versie.

    Er is hier een aanzienlijk voordeel ten opzichte van de native implementatie, waarbij het volledige binaire bestand zelfs met een kleine wijziging wordt gedownload of een complexe binaire vergelijking veroorzaakt. Zo kunnen wij met een relatief kleine belasting een grote webapplicatie updaten.

    Servicemedewerkers werken beter als een verbetering dan als een tijdelijke steunpilaar, dus werk met de cache in plaats van ertegen te vechten.

    Bij zorgvuldig gebruik kunnen maximale leeftijd en variabele inhoud zeer goed zijn

    max-age is vaak de verkeerde keuze voor veranderlijke inhoud, maar niet altijd. Het originele artikel heeft bijvoorbeeld een maximale leeftijd van drie minuten. De raceconditie is geen probleem, aangezien er geen afhankelijkheden zijn op de pagina die hetzelfde cachingpatroon gebruikt (CSS, JS en afbeeldingen gebruiken patroon #1 - onveranderlijke inhoud), al het andere gebruikt dit patroon niet.

    Dit patroon betekent dat ik gemakkelijk een populair artikel kan schrijven, en dat mijn CDN (Cloudflare) de server kan ontlasten, zolang ik maar drie minuten wil wachten totdat het bijgewerkte artikel beschikbaar is voor gebruikers.

    Dit patroon moet zonder fanatisme worden gebruikt. Als ik een nieuwe sectie aan een artikel toevoegde en ernaar linkte vanuit een ander artikel, creëerde ik een afhankelijkheid die moet worden opgelost. De gebruiker kan op de link klikken en een kopie van het artikel krijgen zonder de sectie waarnaar hij op zoek is. Als ik dit wil vermijden, moet ik het artikel vernieuwen, de cacheversie van het artikel uit Cloudflare verwijderen, drie minuten wachten en dan pas de link naar een ander artikel toevoegen. Ja, dit patroon vereist voorzichtigheid.

    Bij correct gebruik zorgt caching voor aanzienlijke prestatieverbeteringen en bandbreedtebesparingen. Geef onveranderlijke inhoud weer als u de URL eenvoudig kunt wijzigen, of gebruik hervalidatie op de server. Combineer inhoud met maximale leeftijd en veranderlijke inhoud als u moedig genoeg bent en er zeker van bent dat uw inhoud geen afhankelijkheden heeft die uit de pas kunnen lopen.

    Door externe CSS en Javascript op te nemen willen we onnodige HTTP-verzoeken tot een minimum beperken.

    Voor dit doel worden .js- en .css-bestanden geleverd met headers die betrouwbare caching garanderen.

    Maar wat doe je als een van deze bestanden tijdens de ontwikkeling verandert? Alle gebruikers hebben de oude versie in hun cache - totdat de cache verouderd is, zullen er veel klachten zijn over de verbroken integratie van de server- en clientonderdelen.

    Een goede caching en versiebeheer elimineert dit probleem volledig en zorgt voor een betrouwbare, transparante synchronisatie van stijl-/scriptversies.

    Eenvoudige ETag-caching

    De eenvoudigste manier om statische bronnen in de cache op te slaan, is door ETag te gebruiken.

    Het is voldoende om de juiste serverinstelling in te schakelen (voor Apache is dit standaard ingeschakeld) - en voor elk bestand in de headers wordt een ETag gegeven - een hash die afhankelijk is van de updatetijd, bestandsgrootte en (op inode-gebaseerd bestand systemen) inode.

    De browser slaat een dergelijk bestand op in de cache en specificeert bij daaropvolgende verzoeken een If-None-Match-header met de ETag van het in de cache opgeslagen document. Na zo'n header te hebben ontvangen, kan de server reageren met code 304 - en dan wordt het document uit de cache gehaald.

    Het ziet er zo uit:

    Eerste verzoek aan de server (cache opschonen) GET /misc/pack.js HTTP/1.1 Host: website

    Over het algemeen voegt de browser meestal een aantal headers toe, zoals User-Agent, Accept, enz. Ze zijn kortheidshalve geknipt.

    Reactie van de server De server antwoordt met een document met code 200 en ETag: HTTP/1.x 200 OK Inhoudscodering: gzip Inhoudstype: tekst/javascript; charset=utf-8 Etag: "3272221997" Accepteerbereik: bytes Inhoudslengte: 23321 Datum: vrijdag 2 mei 2008 17:22:46 GMT Server: lighttpd Volgend browserverzoek Bij het volgende verzoek voegt de browser If-None toe -Match: (ETag in cache): GET /misc/pack.js HTTP/1.1 Host: site If-None-Match: "453700005" Serverantwoord De server ziet er uit - ja, het document is niet gewijzigd. Dit betekent dat u een 304-code kunt uitgeven en het document niet opnieuw kunt verzenden.

    HTTP/1.x 304 Niet gewijzigd Inhoudscodering: gzip Etag: "453700005" Inhoudstype: tekst/javascript; charset=utf-8 Accept-bereiken: bytes Datum: dinsdag, 15 april 2008 10:17:11 GMT

    Een alternatief is dat als het document is gewijzigd, de server eenvoudigweg 200 verzendt met de nieuwe ETag.

  • De combinatie Last-Modified + If-Modified-Since werkt op een vergelijkbare manier:
  • de server verzendt de datum van de laatste wijziging in de Last-Modified header (in plaats van ETag)
  • de browser slaat het document op in de cache en de volgende keer dat er een aanvraag voor hetzelfde document wordt gedaan, verzendt deze de datum van de in de cache opgeslagen versie in de If-Modified-Since-header (in plaats van If-None-Match)
  • de server controleert de datums en als het document niet is gewijzigd, verzendt deze alleen de 304-code, zonder de inhoud.

    Deze methoden werken betrouwbaar en goed, maar de browser moet nog steeds voor elk script of elke stijl een verzoek doen.

    Slimme caching. Versiebeheer

  • De algemene aanpak voor versiebeheer - in een notendop:
  • De versie (of wijzigingsdatum) wordt aan alle scripts toegevoegd. http://site/my.js wordt bijvoorbeeld http://site/my.v1.2.js
  • Alle scripts worden door de browser in de harde cache opgeslagen
  • Bij het updaten van het script verandert de versie naar een nieuwe versie: http://site/my.v2.0.js
  • Het adres is gewijzigd, dus de browser zal het bestand opnieuw opvragen en in de cache opslaan
  • De oude versie 1.2 zal geleidelijk uit de cache vallen

    Harde caching Harde caching

    - een soort voorhamer die verzoeken voor in de cache opgeslagen documenten volledig naar de server spijkert.

    Om dit te doen, voegt u gewoon de headers Expires en Cache-Control: max-age toe.

    Om bijvoorbeeld 365 dagen in PHP te cachen:

    Header("Verloopt: ".gmdate("D, d M Y H:i:s", tijd()+86400*365).." GMT"); header("Cache-Control: max-age="+86400*365);

    Of u kunt de inhoud permanent in de cache opslaan met mod_header in Apache:

    De meeste browsers (Opera, Internet Explorer 6+, Safari) slaan documenten NIET in de cache op als er een vraagteken in het adres staat, omdat ze deze als dynamisch beschouwen.

    Daarom voegen we de versie toe aan de bestandsnaam. Bij dergelijke adressen moet je natuurlijk een oplossing als mod_rewrite gebruiken, we zullen dit later in het artikel bekijken.

    P.S Maar Firefox slaat adressen met vraagtekens op in de cache...

    Automatische naamomzetting

    Laten we eens kijken hoe we automatisch en transparant versies kunnen wijzigen zonder de bestanden zelf te hernoemen.

    Naam met versie -> Bestand

    Het eenvoudigste is om de naam met de versie om te zetten in de originele bestandsnaam.

    Op Apache-niveau kan dit worden gedaan met mod_rewrite:

    RewriteEngine op RewriteRule ^/(.*\.)v+\.(css|js|gif|png|jpg)$ /$1$2 [L]

    Deze regel verwerkt alle css/js/gif/png/jpg-bestanden, waarbij de versie uit de naam wordt verwijderd.

    Bijvoorbeeld:

    /images/logo.v2.gif -> /images/logo.gif
    /css/stijl.v1.27.css -> /css/stijl.css
    /javascript/script.v6.js -> /javascript/script.js

    Maar naast het verwijderen van de versie, moet u ook harde caching-headers aan de bestanden toevoegen. Hiervoor worden de mod_header-richtlijnen gebruikt:

    Koptekst toevoegen "Verloopt" "Ma, 28 juli 2014 23:30:00 GMT" Koptekst toevoegen "Cache-Control" "max-age=315360000"

    En alles bij elkaar implementeert het de volgende Apache-configuratie:

    RewriteEngine op # verwijdert de versie en stelt tegelijkertijd de variabele in voor de versie van het bestand. RewriteRule ^/(.*\.)v+\.(css|js|gif|png|jpg)$ /$1$2 # harde cache versiebestanden Header toevoegen "Verloopt" "ma, 28 juli 2014 23:30:00 GMT" env=VERSIONED_FILE Header toevoegen "Cache-Control" "max-age=315360000" env=VERSIONED_FILE

    Vanwege de manier waarop de mod_rewrite module werkt, moet RewriteRule in het hoofdconfiguratiebestand httpd.conf of in de meegeleverde bestanden worden geplaatst (inbegrepen), maar in geen geval in .htaccess , anders worden de Header-opdrachten eerst uitgevoerd voordat het wordt geïnstalleerd VERSIONED_FILE variabel.

    Headerrichtlijnen kunnen overal voorkomen, zelfs in .htaccess - het maakt niet uit.

    Automatisch versie toevoegen aan bestandsnaam op HTML-pagina

    Hoe u de versie in de naam van het script plaatst, hangt af van uw sjabloonsysteem en, in het algemeen, van de manier waarop u scripts toevoegt (stijlen, enz.).

    Als u bijvoorbeeld de wijzigingsdatum als versie en de Smarty-sjabloonengine gebruikt, kunnen koppelingen als volgt worden ingesteld:

    De versiefunctie voegt de versie toe:

    Functie smarty_version($args)( $stat = stat($GLOBALS["config"]["site_root"].$args["src"]); $version = $stat["mtime"]; echo preg_replace("! \.(+?)$!", ".v$version.\$1", $args["src"]); )

    Resultaat op de pagina:

    Optimalisatie

    Om onnodige statistische oproepen te voorkomen, kunt u een array met een lijst met huidige versies in een afzonderlijke variabele opslaan

    $versions["css"] = array("group.css" => "1.1", "andere.css" => "3.0", )

    In dit geval wordt de huidige versie van de array eenvoudigweg vervangen door de HTML.

    Je kunt beide benaderingen kruisen en tijdens de ontwikkeling een versie produceren op wijzigingsdatum - voor relevantie, en in productie - een versie uit een array, voor prestaties.

    Toepasbaarheid

    Deze cachingmethode werkt overal, inclusief Javascript, CSS, afbeeldingen, Flash-films, enz.

    Het is handig wanneer het document verandert, maar de browser moet altijd de huidige, up-to-date versie hebben.

    Soms kan het nodig zijn om te voorkomen dat de browser een pagina in de cache opslaat, omdat de informatie erop elke keer wordt bijgewerkt. Dit kan het genereren van gegevens zijn volgens geselecteerde filters of andere inhoud die elke keer op een nieuwe manier wordt gemaakt. Kortom, er zijn momenten waarop het nodig is om te voorkomen dat een verraderlijk programma een pagina in de cache opslaat. Vandaag zullen we leren hoe we dit op verschillende manieren kunnen implementeren, met behulp van PHP of HTML of .htaccess.

    Verbiedt paginacaching in HTML

    Dit kan gedaan worden met behulp van metatags. Nu zullen we verschillende opties bekijken om caching te verbieden.

    Verbod op caching door browser en proxyserver

    Schakel paginacaching uit, alleen browser

    Caching instellen voor een specifieke tijd voor de browser

    Met behulp van de onderstaande code kunnen we de browser vertellen hoe lang het document in de cache moet worden bewaard. Hierna wordt de cache bijgewerkt.

    Caching instellen voor een specifieke tijd voor een proxyserver

    Praktisch hetzelfde als in de vorige code, alleen de indicatie is specifiek voor de proxyserver.

    Voorkom paginacaching met PHP

    Praktisch gezien is alles hetzelfde als in het geval van HTML, alleen zullen we informatie weergeven via header-headers. Zo implementeert u een absolute cacheweigering:

    U kunt caching ook voor een bepaalde tijd toestaan. Laten we caching bijvoorbeeld slechts één uur toestaan.

    Voorkom paginacaching met .htaccess

    Om het idee eenvoudiger te implementeren te maken, kan alles op het configuratieniveau van de Apache-server worden gedaan. Voordat we dit doen, moeten we ervoor zorgen dat de benodigde modules werken. Open het Apache-configuratiebestand en zie de volgende afbeelding:

    LoadModule vervalt_module modules/mod_expires.so LoadModule headers_module modules/mod_headers.so ... AddModule mod_expires.c AddModule mod_headers.c

    In het .htaccess-bestand verbieden we feitelijk het cachen van de uitvoergegevens. Zoals we weten, wordt het .htaccess-bestand gedistribueerd naar de map waarin het zich bevindt en naar alle submappen.

    # Header Cache-Control Header toevoegen Cache-Control "no-store, no-cache, must-revalidate" # Header Expires ExpiresActive On ExpiresDefault "nu"

    Het is belangrijk op te merken dat het volledig verbieden van caching de belasting van de server verhoogt. Speel hier daarom voorzichtig mee! Beter nog, stel een specifieke tijd in waarvoor u documenten in de cache kunt opslaan. Laten we caching bijvoorbeeld instellen op 1 uur:

    # Header Cache-Control Header toevoegen Cache-Control "public" # Header Expires ExpiresActive On ExpiresDefault "toegang plus 1 uur"

    Conclusie