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

Mnogi ljudi misle da prema zadanim postavkama CSS datoteke povezane putem veze ili @import nisu predmemorirane. Moram te razočarati. Točno css uključen u zasebna datoteka predmemorirano, i to vrlo dobro, rekao bih izvrsno. Ove informacije su pouzdano provjerene na 6 i novijim i drugim preglednicima. Vrijedno je napomenuti da mnogi ljudi spremaju takve datoteke u predmemoriju divljom brzinom, da tako kažem, zauzimaju prvo mjesto po ovom pitanju. Usput, u mnogim slučajevima upravo ovaj mehanizam Opera ima značajnu brzinu u usporedbi s drugim preglednicima. Ali odmah ću reći da upravo ovo "super" predmemoriranje u Operi igra okrutnu šalu s njim kada se koristi AJAX tehnologija. Dok drugi koristeći AJAXŽene rade promjene, Opera vraća staro. Ali ovo je pjesma o posebnoj temi.

CSS predmemoriranje

ALI! Ipak, neki ljudi imaju problema u tom smjeru. To je obično zbog neispravno konfiguriranog Apache poslužitelja, koji proizvodi ne sasvim ispravna zaglavlja. Pomoću zaglavlja možete kontrolirati predmemoriju datoteka. Prema zadanim postavkama, naravno, predmemorija je uvijek omogućena. Ali ponekad nema potrebe za spremanjem datoteka u predmemoriju. Iz tog razloga, čak i profesionalci počinju plesati s tamburama u vezi HTTP zaglavlja. Ali ako ste pročitali ovaj cijeli članak, onda ste još daleko od upravljanja HTTP zaglavljima. Uvjeravam vas da se u bliskoj budućnosti nećete suočiti s takvim problemom. Pa ipak, ako ste znatiželjni do srži, onda ću vam ukratko reći kako se to događa.

  • šalje HTTP zaglavlje na WEB poslužitelj - kažu, slušaj, slatka paprika, daj mi CSS datoteka, inace imam CSS, ali u zadnje vrijeme promjene su ovakve i onakve.
  • A poslužitelj mu odgovara, dušo, nije bilo promjena od tog trenutka, slobodno uzmi i koristi svoj stari CSS.
  • Ako se CSS promijenio, tada preglednik glupo ažurira CSS u svojoj predmemoriji.
  • E, sad, ako nisam umoran, onda malo znanstvenog smeća od nekakvog eksperimenta.

    Odmah ću reći da će početnici na WEB-u slabo razumjeti donji tekst. Ovo će uglavnom biti korisno onima koji se suočavaju sa zadatkom onemogućavanja i omogućavanja predmemorije.

    Svi eksperimenti provedeni su na stvarnom, plaćenom. Dobar hoster, da tako kažem, koji vam omogućuje promjenu strukture HTTP zaglavlja bez paranoje da će biti hakiran na temelju HTTP zaglavlja :)

    Načini rada preglednika

    Dakle, svaki preglednik ima 2 načina rada:

    1. Zadani način rada, povratno zaglavlje:

    Kontrola predmemorije: bez pohrane, bez predmemorije, mora se ponovo potvrditi, naknadna provjera=0, prethodna provjera=0

    2. Način rada s omogućenim predmemoriranjem, vraćeno zaglavlje:

    Kontrola predmemorije: privatno, max-age=10800, prethodna provjera=10800

    Zatim opisujem ponašanje preglednika FireFox 3.5 i novijih

    U prvom načinu rada čvrsto sprema vanjske JavaScript datoteke i čak ne provjerava njihova ažuriranja, osim ako je stranica prisiljena osvježiti se. CSS se provjerava zahtjevom zaglavlja.

    If-Modified-Since: "trenutni datum" GMT If-None-Match: "vaš hash kod"

    To jest, CSS se ponovno učitava samo ako je stvarno ažuriran.

    Drugo, drugi način potpuno prestaje ažurirati stranicu. Odnosno, čak i ako smo promijenili sadržaj prikazan na stranici u bazi podataka, ona to ne prikazuje, čak i ako je prisilno ažuriramo, jer šalje zahtjev:

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

    i dobije odgovor:

    HTTP/1.1 304 Nije izmijenjeno

    Internet Explorer 8 (IE8)

    U prvom načinu, Internet Explorer šalje zahtjeve If-Modified-Since & If-None-Match i za JavaScript i za CSS, odnosno učitava JavaScript i CSS samo ako su stvarno ažurirani. Ista stvar se događa ako prisilno osvježite stranicu.

    U drugom načinu, Internet Explorer također šalje zahtjeve If-Modified-Since & If-None-Match i za JavaScript i za css. Ali pritom niti ne pokušava učitati/ažurirati samu stranicu, odnosno niti ne šalje zahtjev, odnosno vaš js/css će se ažurirati, ali predložak i sadržaj stranice neće. Čak ni prisilno osvježavanje stranice ne pomaže u ažuriranju sadržaja.

    Opera 10 i starije

    U prvom načinu rada Opere, u prvom načinu, ažuriranje js-a i CSS-a ovisi o tome na koju je vrijednost opcija Provjeri slike postavljena u postavkama. Ako je opcija postavljena na Uvijek, onda Opera šalje zahtjeve s If-Modified-Since & If-None-Match za provjeru ažuriranja js i css. Ako je vrijednost postavljena, na primjer, 5 sati, tada će se provjeravati u skladu s tim svakih 5 sati ili prisilnim osvježavanjem stranice.

    Drugo, Opera ne provjerava ažuriranje js & CSS (ne pravi GET zahtjeve), a također ne pravi GET zahtjev samoj stranici, odnosno nećemo vidjeti niti ažuriranje js & css niti ažuriranje sadržaja, kao i u drugim slučajevima i u drugim preglednicima. Ali s prisilnim ažuriranjem Opera je bolja. Za razliku od IE & FF, Opera izričito zahtijeva sadržaj stranice bez If-Modified-Since & If-None-Match. Zahtjevi za ažuriranje js-a i CSS-a tijekom prisilnog ažuriranja već dolaze s If-Modified-Since & If-None-Match.

    zaključke
  • Predmemoriranje, ako ne razumijete točno kako funkcionira različitim preglednicima a kakve su posljedice – dosta opasna stvar.
  • Predmemoriranje se može omogućiti samo ako se stranica rijetko ažurira (odnosno, ako stranica nema stranice koje se ažuriraju u stvarnom vremenu), a čak iu tom slučaju potrebno je postaviti ograničenje na razdoblje ograničenja predmemoriranja (npr. , nekoliko sati ili dan)
  • FireFox se, po mom mišljenju, ponaša malo pametnije od IE-a, jer čak i s isključenim predmemoriranjem ne provjerava stalno ažuriranja JavaScripta, što se čini logičnim, jer se JavaScript ažurira vrlo rijetko.
  • Opera vam omogućuje da fleksibilno kontrolirate ažuriranje slika, JavaScripta i CSS-a pomoću postavke Provjeri slike, što je plus. Opera se također ponaša bolje od IE & FF s uključenim predmemoriranjem i prisilnim ažuriranjem, budući da, da vas podsjetim, Opera u ovom slučaju potpuno ažurira sadržaj stranice, a IE & FF će vas ostaviti blaženo nesvjesnima.
  • Sretno vam i profitabilnim stranicama.

    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 najbolje prakse predmemoriranje se odnosi na jedan od dva uzorka:

    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); U Node.js također postoje vrlo male biblioteke 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, zbog čega mi treba prilika brzo ažuriranje 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. Server, 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 spremati u predmemoriju", 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 keširanje.

    U ovom obrascu odgovoru možemo dodati ETag (ID 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 "Upotrijebi ono što imaš, tvoja 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 mogu se pojaviti i problemi s mrežnim zahtjevima u uzorku 2. 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 čini se da je nešto pošlo po zlu! Sve je polomljeno! Što se događa? 10:29

    Ovaj obrazac 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 neprestano 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 primjeru poništavam predmemoriju koristeći nasumični 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 neka vrsta implementacije prvog uzorka koji koristi 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 radniku, 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 za korijensku stranicu, 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, a ne 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 klikom na poveznicu 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 koristi ispravno, 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.

    Povezivanje vanjski CSS i Javascript, želimo svesti nepotrebne HTTP zahtjeve na minimum.

    U tu svrhu, .js i .css datoteke poslužuju se sa zaglavljima koja osiguravaju pouzdano predmemoriranje.

    Ali što učiniti kada se jedna od ovih datoteka promijeni tijekom razvoja? Svi korisnici imaju staru verziju u svom cacheu - dok cache ne zastari, bit će puno pritužbi na pokvarenu integraciju poslužiteljskog i klijentskog dijela.

    Pravilno predmemorija i verzija u potpunosti eliminiraju ovaj problem i pružaju pouzdanu, transparentnu sinkronizaciju verzija stila/skripte.

    Jednostavno ETag predmemoriranje

    Najjednostavniji način predmemoriranja statičkih resursa je korištenje ETaga.

    Dovoljno je omogućiti odgovarajuću postavku poslužitelja (za Apache je uključeno prema zadanim postavkama) - i za svaku datoteku u zaglavljima bit će dodan ETag - hash koji ovisi o vremenu ažuriranja, veličini datoteke i (na bazi inode-a) datotečni sustavi) inod.

    Preglednik pohranjuje takvu datoteku u predmemoriju i, na naknadne zahtjeve, navodi zaglavlje If-None-Match s ETagom predmemoriranog dokumenta. Nakon što primi takvo zaglavlje, poslužitelj može odgovoriti s kodom 304 - i tada će dokument biti preuzet iz predmemorije.

    Ovako izgleda:

    Prvi zahtjev poslužitelju (čišćenje predmemorije) GET /misc/pack.js HTTP/1.1 Host: web stranica

    Općenito, preglednik obično dodaje hrpu zaglavlja kao što su User-Agent, Accept itd. Izrezani su radi kratkoće.

    Odgovor poslužitelja Poslužitelj odgovara dokumentom s kodom 200 i ETagom: HTTP/1.x 200 OK Content-Encoding: gzip Content-Type: text/javascript; charset=utf-8 Etag: "3272221997" Accept-Ranges: bytes Content-Length: 23321 Datum: Fri, 02 May 2008 17:22:46 GMT Server: lighttpd Sljedeći zahtjev preglednika Na sljedećem zahtjevu, preglednik dodaje If-None -Podudaranje: (spremljeno u predmemoriju ETag): GET /misc/pack.js HTTP/1.1 Domaćin: stranica If-None-Match: "453700005" Odgovor poslužitelja Poslužitelj izgleda - da, dokument se nije promijenio. To znači da možete izdati kod 304 i ne poslati ponovno dokument. HTTP/1.x 304 Nije izmijenjeno Kodiranje sadržaja: gzip Etag: "453700005" Vrsta sadržaja: tekst/javascript; charset=utf-8 Accept-Ranges: bytes Datum: utorak, 15. travnja 2008. 10:17:11 GMT

    Alternativa je ako se dokument promijenio, tada poslužitelj jednostavno pošalje 200 s novom ETagom.

    Kombinacija Last-Modified + If-Modified-Since funkcionira na sličan način:

  • poslužitelj šalje datum zadnje izmjene u zaglavlju Last-Modified (umjesto ETag)
  • preglednik sprema dokument u predmemoriju, a sljedeći put kada se podnese zahtjev za isti dokument, šalje datum predmemorirane verzije u zaglavlju If-Modified-Since (umjesto If-None-Match)
  • server provjerava datume, i ako dokument nije promijenjen, šalje samo kod 304, bez sadržaja.
  • Ove metode rade pouzdano i dobro, ali preglednik ipak mora napraviti zahtjev za svaku skriptu ili stil.

    Pametno predmemoriranje. Verziranje

    Opći pristup za izradu verzija - ukratko:

  • Verzija (ili datum izmjene) dodaje se svim skriptama. Na primjer, http://site/my.js postat će http://site/my.v1.2.js
  • Sve skripte preglednik čvrsto predmemorira
  • Prilikom ažuriranja skripte, verzija se mijenja u novu: http://site/my.v2.0.js
  • Adresa se promijenila, pa će preglednik ponovo zatražiti i spremiti datoteku u predmemoriju
  • Stara verzija 1.2 postupno će nestati iz predmemorije
  • Teško predmemoriranje

    Teško predmemoriranje- neka vrsta malja koji u potpunosti zabija zahtjeve poslužitelju za predmemorirane dokumente.

    Da biste to učinili, samo dodajte zaglavlja Expires i Cache-Control: max-age.

    Na primjer, za predmemoriju za 365 dana u PHP-u:

    Header("Ističe: ".gmdate("D, d M Y H:i:s", vrijeme()+86400*365)." GMT"); zaglavlje ("Cache-Control: max-age="+86400*365);

    Ili možete trajno spremiti sadržaj u predmemoriju koristeći mod_header u Apacheu:

    Nakon što primi takva zaglavlja, preglednik dugo predmemorira dokument. Sav daljnji pristup dokumentu bit će poslužen izravno iz predmemorije preglednika, bez kontaktiranja poslužitelja.

    Većina preglednika (Opera, Internet Explorer 6+, Safari) NE KEŠIRA dokumente ako u adresi postoji upitnik, jer ih smatraju dinamičnim.

    Zato nazivu datoteke dodajemo verziju. Naravno, s takvim adresama morate koristiti rješenje kao što je mod_rewrite, to ćemo pogledati kasnije u članku.

    P.S. Ali Firefox sprema adrese s upitnicima...

    Automatska rezolucija imena

    Pogledajmo kako automatski i transparentno mijenjati verzije bez preimenovanja samih datoteka.

    Naziv s verzijom -> Datoteka

    Najjednostavnije je naziv s verzijom pretvoriti u originalni naziv datoteke.

    Na razini Apachea to se može učiniti s mod_rewrite:

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

    Ovo pravilo obrađuje sve css/js/gif/png/jpg datoteke, uklanjajući verziju iz naziva.

    Na primjer:

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

    Ali osim izrezivanja verzije, datotekama morate dodati i zaglavlja tvrdog predmemoriranja. Za to se koriste direktive mod_header:

    Zaglavlje dodaj "Ističe" "Mon, 28 Jul 2014 23:30:00 GMT" Zaglavlje dodaj "Cache-Control" "max-age=315360000"

    I sve zajedno implementira sljedeću Apache konfiguraciju:

    RewriteEngine on # uklanja verziju, a u isto vrijeme postavlja varijablu da je datoteka verzionirana RewriteRule ^/(.*\.)v+\.(css|js|gif|png|jpg)$ /$1$2 # hard cache verzionirane datoteke Zaglavlje dodaj "Ističe" "Mon, 28 Jul 2014 23:30:00 GMT" env=VERSIONED_FILE Zaglavlje dodaj "Cache-Control" "max-age=315360000" env=VERSIONED_FILE

    Zbog načina na koji mod_rewrite modul radi, RewriteRule treba postaviti u glavni konfiguracijska datoteka httpd.conf ili uključene datoteke, ali nikada u .htaccess, inače će se prvo pokrenuti naredbe zaglavlja, prije nego što se postavi varijabla VERSIONED_FILE.

    Direktive zaglavlja mogu biti bilo gdje, čak i u .htaccessu - nije važno.

    Automatsko dodavanje verzije nazivu datoteke na HTML stranici

    Kako staviti verziju u ime skripte ovisi o vašem sustavu predložaka i, općenito, o načinu na koji dodajete skripte (stilove, itd.).

    Na primjer, kada koristite datum izmjene kao verziju i Smarty predložak, veze se mogu postaviti ovako:

    Funkcija verzije dodaje verziju:

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

    Rezultat na stranici:

    Optimizacija

    Kako biste izbjegli nepotrebne pozive statistike, možete pohraniti niz s popisom trenutnih verzija u zasebnu varijablu

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

    U ovom slučaju, trenutna verzija iz niza jednostavno se zamjenjuje u HTML.

    Možete ukrstiti oba pristupa i tijekom razvoja proizvesti verziju prema datumu izmjene - za relevantnost, au proizvodnji - verziju iz niza, za performanse.

    Primjenjivost

    Ova metoda predmemoriranja radi posvuda, uključujući Javascript, CSS, slike, Flash filmove itd.

    Korisno je kad god se dokument mijenja, ali preglednik uvijek treba imati trenutnu, ažurnu verziju.