Stilovi predmemoriranja. Osnove predmemoriranja klijenata jasnim riječima i primjerima. Last-modified, Etag, Expires, Cache-control: max-age i druga zaglavlja. URL otisak prsta

💖 Sviđa li vam se? Podijelite vezu sa svojim prijateljima

Ispravno konfigurirano predmemoriranje pruža velike prednosti u izvedbi, štedi propusnost i smanjuje troškove poslužitelja, ali mnoga mjesta loše implementiraju predmemoriranje, stvarajući uvjete utrke koji uzrokuju da međusobno povezani resursi ne budu sinkronizirani.

Velika većina najboljih praksi predmemoriranja spada u jedan od dva obrasca:

Uzorak br. 1: nepromjenjivi sadržaj i duga predmemorija max-age Cache-Control: max-age=31536000
  • Sadržaj URL-a se ne mijenja, dakle...
  • Preglednik ili CDN mogu lako spremiti resurs u predmemoriju godinu dana
  • Predmemorirani sadržaj koji je mlađi od navedene maksimalne dobi može se koristiti bez savjetovanja s poslužiteljem

Stranica: Hej, trebam "/script-v1.js", "/styles-v1.css" i "/cats-v1.jpg" 10:24

Cash: Ja sam prazan, a ti, Server? 10:24

Poslužitelj: OK, evo ih. Usput, Cash, treba ih koristiti godinu dana, ne više. 10:25

Gotovina: Hvala! 10:25

Stranica: Hura! 10:25

Sljedeći dan

Stranica: Hej, trebam "/script-v2 .js" , "/styles-v2 .css" i "/cats-v1.jpg" 08:14

Gotovina: Postoji slika s mačkama, ali ne i ostalo. poslužitelj? 08:14

Poslužitelj: Jednostavno - evo novog CSS-a i JS-a. Još jednom, gotovina: njihov rok trajanja nije duži od godinu dana. 08:15 sati

Gotovina: Super! 08:15 sati

Stranica: Hvala! 08:15 sati

Gotovina: Hmm, već neko vrijeme nisam koristio "/script-v1.js" & "/styles-v1.css". Vrijeme je da ih uklonite. 12:32

Koristeći ovaj obrazac, nikada ne mijenjate sadržaj određenog URL-a, mijenjate sam URL:

Svaki URL ima nešto što se mijenja zajedno sa sadržajem. To može biti broj verzije, datum izmjene ili hash sadržaja (što sam odabrao za svoj blog).

Većina okvira na strani poslužitelja ima alate koji vam omogućuju da s lakoćom radite ovakve stvari (u Djangu koristim Manifest​Static​Files​Storage); Postoje i vrlo male biblioteke u Node.js koje rješavaju iste probleme, na primjer, gulp-rev.

Međutim, ovaj uzorak nije prikladan za stvari poput članaka i postova na blogu. Njihovim URL-ovima nije moguće odrediti verziju i njihov se sadržaj može promijeniti. Ozbiljno, često imam gramatičke i interpunkcijske pogreške i moram biti u mogućnosti brzo ažurirati sadržaj.

Uzorak #2: promjenjivi sadržaj koji se uvijek provjerava na poslužitelju Cache-Control: bez predmemorije
  • Sadržaj URL-a će se promijeniti, što znači...
  • Bilo koja lokalno predmemorirana verzija ne može se koristiti bez navođenja poslužitelja.

Stranica: Hej, trebam sadržaj "/o/" i "/sw.js" 11:32

Cash: Ne mogu ti pomoći. poslužitelj? 11:32

Poslužitelj: Ima ih. Gotovina, imajte ih kod sebe, ali pitajte me prije nego ih upotrijebite. 11:33

Gotovina: Točno! 11:33

Stranica: Hvala! 11:33

Sljedeći dan

Stranica: Hej, trebam ponovno sadržaj "/o/" i "/sw.js" 09:46

Gotovina: Samo minutu. Poslužitelju, jesu li moje kopije u redu? Kopija "/o/" je od ponedjeljka, a "/sw.js" je od jučer. 09:46 sati

Poslužitelj: "/sw.js" nije promijenjen... 09:47

Gotovina: Cool. Stranica, zadržite "/sw.js" . 09:47 sati

Poslužitelj: …ali ja imam “/o/” nova verzija. Cash, drži, ali kao prošli put, ne zaboravi me prvo pitati. 09:47 sati

Gotovina: Shvaćam! 09:47 sati

Stranica: Sjajno! 09:47 sati

Napomena: bez predmemoriranja ne znači "ne predmemorirati", to znači "provjeriti" (ili ponovno potvrditi) predmemorirani resurs na poslužitelju. A no-store govori pregledniku da uopće ne sprema predmemoriju. Također, must-revalidate ne znači obaveznu ponovnu provjeru valjanosti, već da se predmemorirani resurs koristi samo ako je mlađi od specificirane max-age, a samo u suprotnom se ponovno provjerava. Ovako je sve počelo ključne riječi za predmemoriju.

U ovom obrascu odgovoru možemo dodati ETag (identifikator verzije po vašem izboru) ili zaglavlje Last-Modified. Sljedeći put kada klijent zatraži sadržaj, izlazi If-None-Match ili If-Modified-Since, respektivno, dopuštajući poslužitelju da kaže "Upotrijebite ono što imate, vaša predmemorija je ažurna", tj. vrati HTTP 304.

Ako slanje ETag / Last-Modified nije moguće, poslužitelj uvijek šalje cijeli sadržaj.

Ovaj uzorak uvijek zahtijeva mrežne pozive, tako da nije tako dobar kao prvi uzorak, koji može raditi bez mrežnih zahtjeva.

Nije neuobičajeno da nemamo infrastrukturu za prvi uzorak, ali problemi s mrežnim zahtjevima u uzorku 2 mogu se pojaviti i kao rezultat toga, koristi se srednja opcija: kratka maksimalna starost i promjenjivi sadržaj. Ovo je loš kompromis.

Korištenje max-age s promjenjivim sadržajem općenito je pogrešan izbor

I, nažalost, to je uobičajeno; Github stranice su primjer.

Zamisliti:

  • /članak/
  • /styles.css
  • /script.js

Sa zaglavljem poslužitelja:

Cache-Control: obavezna ponovna provjera valjanosti, max-age=600

  • promjene sadržaja URL-a
  • Ako preglednik ima predmemoriranu verziju noviju od 10 minuta, koristi se bez konzultacije s poslužiteljem
  • Ako nema takve predmemorije, koristi se mrežni zahtjev, ako je moguće s If-Modified-Since ili If-None-Match

Stranica: Hej, trebam "/article/", "/script.js" i "/styles.css" 10:21

Cash: Nemam ništa, kao ti, Server? 10:21

Poslužitelj: Nema problema, evo ih. Ali zapamti, gotovina: mogu se iskoristiti u sljedećih 10 minuta. 10:22

Gotovina: Da! 10:22

Stranica: Hvala! 10:22

Stranica: Hej, opet trebam "/article/", "/script.js" i "/styles.css" 10:28

Cash: Ups, žao mi je, ali izgubio sam "/styles.css", ali imam sve ostalo, izvolite. Poslužitelju, možete li prilagoditi "/styles.css" za mene? 10:28

Poslužitelj: Polako, već se promijenio od kad ste ga prošli put uzeli. Možete ga sigurno koristiti sljedećih 10 minuta. 10:29

Gotovina: Nema problema. 10:29

Stranica: Hvala! Ali izgleda da je nešto pošlo po zlu! Sve je polomljeno! Što se događa? 10:29

Ovaj uzorak ima pravo na život tijekom testiranja, ali kvari sve u stvarnom projektu i vrlo ga je teško pratiti. U gornjem primjeru, poslužitelj je ažurirao HTML, CSS i JS, ali stranica se prikazuje sa starim predmemoriranim HTML-om i JS-om, plus ažuriranim CSS-om s poslužitelja. Neusklađenost verzija sve uništava.

Često kada napravimo značajne promjene u HTML-u, promijenimo i CSS kako bi ispravno odražavao novu strukturu i JavaScript kako bismo bili u toku sa sadržajem i stilom. Svi ovi resursi su neovisni, ali zaglavlja predmemoriranja to ne mogu izraziti. Kao rezultat toga, korisnici se mogu pronaći Najnovija verzija jedan/dva resursa i stara verzija ostalih.

max-age se postavlja u odnosu na vrijeme odgovora, tako da ako se svi resursi prenesu kao dio jedne adrese, isteći će u isto vrijeme, ali još uvijek postoji mala vjerojatnost desinkronizacije. Ako imate stranice koje ne uključuju JavaScript ili uključuju druge stilove, njihovi datumi isteka predmemorije neće biti sinkronizirani. I što je još gore, preglednik stalno izvlači sadržaj iz predmemorije, ne znajući da su HTML, CSS i JS međusobno ovisni, tako da može sretno povući jednu stvar s popisa i zaboraviti na sve ostalo. Uzimajući u obzir sve ove čimbenike zajedno, trebali biste shvatiti da je vjerojatnost neusklađenih verzija prilično velika.

Za korisnika, rezultat može biti pokvaren izgled stranice ili drugi problemi. Od malih kvarova do potpuno neupotrebljivog sadržaja.

Srećom, korisnici imaju izlaz u slučaju nužde...

Ponekad pomaže osvježavanje stranice

Ako se stranica učitava osvježavanjem, preglednici uvijek izvode ponovnu provjeru valjanosti na strani poslužitelja, zanemarujući max-age. Stoga, ako je korisniku nešto pokvareno zbog max-age, jednostavno osvježavanje stranice može sve popraviti. Ali, naravno, nakon što se žlice pronađu, talog će i dalje ostati i odnos prema vašoj stranici bit će nešto drugačiji.

Servisni radnik može produžiti vijek trajanja ovih grešaka

Na primjer, imate ovakvog servisera:

Const verzija = "2"; self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => cache.addAll([ "/styles.css", "/script .js" ]))); )); self.addEventListener("aktiviraj", event => ( // …izbriši stare predmemorije… )); self.addEventListener("fetch", event => ( event.respondWith(caches.match(event.request) .then(response => response || fetch(event.request))); ));

Ovaj uslužni radnik:

  • sprema skriptu i stilove
  • koristi predmemoriju ako postoji podudaranje, inače pristupa mreži

Ako promijenimo CSS/JS, također povećavamo broj verzije, što pokreće ažuriranje. Međutim, budući da addAll prvi pristupa predmemoriji, možemo doći u stanje utrke zbog maksimalne dobi i neusklađenih CSS & JS verzija.

Nakon što su predmemorirani, imat ćemo nekompatibilne CSS & JS do sljedećeg ažuriranja uslužnog radnika - a to je osim ako ponovno ne uđemo u stanje utrke tijekom ažuriranja.

Možete preskočiti predmemoriranje u uslužnom radniku:

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" )) ])));

Nažalost, opcije za predmemoriju nisu podržane u Chromeu/Operi i upravo su dodane u noćnu verziju Firefoxa, ali to možete učiniti sami:

Self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => Promise.all([ "/styles.css", "/script .js" ].map(url => ( // cache-bust korištenjem nasumičnog niza upita return fetch(`$(url)?$(Math.random())`).then(response => ( // neuspjeh na 404, 500 itd. if (!response.ok) throw Error("Not ok"); return cache.put(url, response )) ))));

U ovom sam primjeru poništio predmemoriju pomoću slučajni broj, ali možete ići dalje i dodati hash sadržaja prilikom izgradnje (ovo je slično onome što radi sw-precache). Ovo je vrsta implementacije prvog uzorka s koristeći JavaScript, ali radi samo s uslužnim radnikom, ne s preglednicima i CDN-om.

Servisni radnici i HTTP predmemorija odlično funkcioniraju zajedno, nemojte ih tjerati da se svađaju!

Kao što vidite, možete zaobići greške u predmemoriranju u svom uslužnom alatu, ali bolje je riješiti korijen problema. Ispravna postavka predmemoriranje ne samo da olakšava posao servisnog radnika, već pomaže i preglednicima koji ne podržavaju servisne radnike (Safari, IE/Edge), a također vam omogućuje da izvučete najviše iz svog CDN-a.

Ispravna zaglavlja predmemoriranja također mogu znatno olakšati ažuriranje uslužnog radnika.

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

Ovdje sam predmemorirao korijensku stranicu s uzorkom #2 (ponovna provjera valjanosti na strani poslužitelja) i sve ostale resurse s uzorkom #1 (nepromjenjivi sadržaj). Svako ažuriranje uslužnog radnika uzrokovat će zahtjev prema korijenskoj stranici, a svi ostali resursi bit će učitani samo ako se njihov URL promijenio. To je dobro jer štedi promet i poboljšava izvedbu, bez obzira na to nadograđujete li prethodnu ili vrlo stara verzija.

Ovdje postoji značajna prednost u odnosu na nativnu implementaciju, gdje se cijela binarna datoteka preuzima čak i uz malu promjenu ili uzrokuje složenu binarnu usporedbu. Na taj način možemo ažurirati veliku web aplikaciju s relativno malim opterećenjem.

Servisni radnici bolje funkcioniraju kao poboljšanje nego kao privremena štaka, stoga radite s predmemorijom umjesto da se borite s njom.

Ako se pažljivo koristi, maksimalna dob i promjenjivi sadržaj mogu biti vrlo dobri

max-age je vrlo često pogrešan izbor za promjenjivi sadržaj, ali ne uvijek. Na primjer, izvorni članak ima maksimalnu starost od tri minute. Stanje utrke nije problem jer nema ovisnosti o stranici koja koristi isti uzorak predmemoriranja (CSS, JS i slike koriste uzorak #1 - nepromjenjivi sadržaj), sve ostalo ne koristi ovaj obrazac.

Ovaj obrazac znači da mogu lako napisati popularan članak, a moj CDN (Cloudflare) može ukloniti opterećenje s poslužitelja, sve dok sam spreman čekati tri minute da ažurirani članak bude dostupan korisnicima.

Ovaj obrazac treba koristiti bez fanatizma. Ako sam članku dodao novi odjeljak i povezao se na njega iz drugog članka, stvorio sam ovisnost koja se mora riješiti. Korisnik može kliknuti na poveznicu i dobiti kopiju članka bez željenog odjeljka. Ako to želim izbjeći, trebao bih osvježiti članak, izbrisati predmemoriranu verziju članka iz Cloudflarea, pričekati tri minute i tek onda dodati poveznicu na drugi članak. Da, ovaj obrazac zahtijeva oprez.

Kada se pravilno koristi, predmemorija pruža značajna poboljšanja performansi i uštedu propusnosti. Poslužite nepromjenjivi sadržaj ako možete jednostavno promijeniti URL ili upotrijebite ponovnu provjeru valjanosti na strani poslužitelja. Pomiješajte maksimalnu dob i promjenjivi sadržaj ako ste dovoljno hrabri i uvjereni da vaš sadržaj nema ovisnosti koje bi mogle biti neusklađene.

Prilikom izmjena na web stranicama često se susrećemo s činjenicom da se sadržaji stranica, css datoteke i skripte (.js) preglednik pohranjuju u predmemoriju i ostaju nepromijenjeni dosta dugo vremena. To dovodi do činjenice da je potrebno naviknuti klijente na složene kombinacije F5 ili Ctrl + F5, kako bi se učinjene promjene odrazile u svim preglednicima. I s vremena na vrijeme provjerite jesu li pritisnuti.

Proces je prilično naporan i nezgodan. Možete, naravno, izaći iz situacije tako što ćete svaki put preimenovati datoteke, ali opet je nezgodno.

Međutim, postoji način koji će nam omogućiti da ostanemo s istim imenima i resetiramo keširanje .css ili .js datoteka u trenutku kada nam zatreba. I zauvijek zaboravite na Ctrl + F5.

Zaključak je da ćemo našim .css ili .js datotekama na kraju priložiti pseudoparametar koji ćemo povremeno mijenjati, čime ćemo poništiti predmemoriju u pregledniku.

Dakle, ulazak u izvorni kod sada će izgledati ovako:

Gdje je 186485 proizvoljna kombinacija koja će ispisati istu datoteku, ali je preglednik tumači kao novu, zahvaljujući pseudo-parametru ?186485

Sada, kako ne bismo svaki put mijenjali sva pojavljivanja našeg parametra, postavit ćemo ga u php datoteku, koju ćemo povezati na sva mjesta koja su nam potrebna:



reci prijateljima
Pročitajte također