Osnove predpomnjenja strank v jasnih besedah ​​in primerih. Last-modified, Etag, Expires, Cache-control: max-age in druge glave. Najboljše prakse predpomnjenja Preprosto predpomnjenje ETag

Z vključitvijo zunanjega CSS in Javascripta želimo zmanjšati nepotrebne zahteve HTTP na minimum.

V ta namen so datoteke .js in .css postrežene z glavami, ki zagotavljajo zanesljivo predpomnjenje.

Toda kaj storite, ko se ena od teh datotek med razvojem spremeni? Vsi uporabniki ga imajo v predpomnilniku stara različica- dokler predpomnilnik ne bo zastarel, bo veliko pritožb zaradi pokvarjene integracije strežniškega in odjemalskega dela.

Pravilno predpomnjenje in ustvarjanje različic popolnoma odpravi to težavo in zagotavlja zanesljivo, pregledno sinhronizacijo različic sloga/skripta.

Preprosto predpomnjenje ETag

Najenostavnejši način za predpomnjenje statičnih virov je uporaba ETag.

Dovolj je, da omogočite ustrezno nastavitev strežnika (za Apache je privzeto omogočena) - in za vsako datoteko v glavah bo podana ETag - zgoščena vrednost, ki je odvisna od časa posodobitve, velikosti datoteke in (na osnovi inode datotečni sistemi) inode.

Brskalnik shrani tako datoteko v predpomnilnik in ob nadaljnjih zahtevah določi glavo If-None-Match z oznako ETag predpomnjenega dokumenta. Ko prejme takšno glavo, lahko strežnik odgovori s kodo 304 - in nato bo dokument vzet iz predpomnilnika.

Videti je takole:

Prva zahteva strežniku (čiščenje predpomnilnika) GET /misc/pack.js HTTP/1.1 Gostitelj: spletno mesto

Na splošno brskalnik običajno doda kup glav, kot so User-Agent, Accept itd. Odrezani so zaradi kratkosti.

Odziv strežnika Strežnik odgovori z dokumentom s kodo 200 in ETag: HTTP/1.x 200 OK Content-Encoding: gzip Content-Type: text/javascript; charset=utf-8 Etag: "3272221997" Accept-Ranges: bytes Content-Length: 23321 Date: Fri, 02 May 2008 17:22:46 GMT Server: lighttpd Naslednja zahteva brskalnika Pri naslednji zahtevi brskalnik doda možnost If-None -Match: (cached ETag): GET /misc/pack.js HTTP/1.1 Host: site If-None-Match: "453700005" Server response Strežnik je videti - ja, dokument se ni spremenil. To pomeni, da lahko izdate kodo 304 in dokumenta ne pošljete znova. HTTP/1.x 304 ni spremenjeno Kodiranje vsebine: gzip Etag: "453700005" Vrsta vsebine: besedilo/javascript; charset=utf-8 Accept-Ranges: bytes Datum: torek, 15. april 2008 10:17:11 GMT

Alternativna možnost- če se je dokument spremenil, potem strežnik preprosto pošlje 200 z novim ETagom.

Kombinacija Last-Modified + If-Modified-Since deluje na podoben način:

  • strežnik pošlje datum zadnje spremembe v glavi Last-Modified (namesto ETag)
  • brskalnik predpomni dokument in naslednjič, ko je podana zahteva za isti dokument, pošlje datum predpomnjene različice v glavi If-Modified-Since (namesto If-None-Match)
  • strežnik preveri datume in če dokument ni spremenjen, pošlje samo kodo 304, brez vsebine.
  • Te metode delujejo zanesljivo in dobro, vendar mora brskalnik še vedno narediti zahtevo za vsak skript ali slog.

    Pametno predpomnjenje. Versioning

    Splošni pristop k različicam – na kratko:

  • Različica (ali datum spremembe) je dodana vsem skriptom. Na primer, http://site/my.js bo postal http://site/my.v1.2.js
  • Vse skripte brskalnik trdo predpomni
  • Pri posodobitvi skripta se različica spremeni v novo: http://site/my.v2.0.js
  • Naslov se je spremenil, zato bo brskalnik znova zahteval in predpomnil datoteko
  • Stara različica 1.2 bo postopoma padla iz predpomnilnika
  • Trdo predpomnjenje

    Trdo predpomnjenje- nekakšno kladivo, ki popolnoma zabije zahteve do strežnika za predpomnjene dokumente.

    Če želite to narediti, samo dodajte glavi Expires in Cache-Control: max-age.

    Na primer, za predpomnilnik za 365 dni v PHP:

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

    Ali pa lahko trajno predpomnite vsebino z mod_header v Apache:

    Po prejemu takšnih glav brskalnik dolgo časa trdo predpomni dokument. Vsi nadaljnji dostopi do dokumenta bodo postreženi neposredno iz predpomnilnika brskalnika, brez stika s strežnikom.

    Večina brskalnikov (Opera, internet Explorer 6+, Safari) NE predpomnite dokumentov, če je v naslovu vprašaj, ker veljajo za dinamične.

    Zato k imenu datoteke dodamo različico. Seveda morate pri takšnih naslovih uporabiti rešitev, kot je mod_rewrite, to si bomo ogledali kasneje v članku.

    P.S. Toda Firefox predpomni naslove z vprašaji ...

    Samodejna ločljivost imena

    Poglejmo, kako samodejno in pregledno spremeniti različice brez preimenovanja samih datotek.

    Ime z različico -> Datoteka

    Najenostavneje je spremeniti ime z različico v izvirno ime datoteke.

    Na ravni Apache je to mogoče storiti z mod_rewrite:

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

    To pravilo obdela vse datoteke css/js/gif/png/jpg in odstrani različico iz imena.

    Na primer:

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

    Toda poleg izrezovanja različice morate datotekam dodati tudi glave za trdo predpomnjenje. Za to se uporabljajo direktive mod_header:

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

    In vse skupaj izvaja naslednjo konfiguracijo Apache:

    RewriteEngine on # odstrani različico in hkrati nastavi spremenljivko, da je datoteka verzionirana RewriteRule ^/(.*\.)v+\.(css|js|gif|png|jpg)$ /$1$2 # trdi predpomnilnik datoteke z različicami Glava dodaj "Poteče" "Mon, 28 Jul 2014 23:30:00 GMT" env=VERSIONED_FILE Glava dodaj "Cache-Control" "max-age=315360000" env=VERSIONED_FILE

    Zaradi načina delovanja modula mod_rewrite je treba RewriteRule postaviti v glavni konfiguracijsko datoteko httpd.conf ali vključene datoteke, vendar nikoli v .htaccess, sicer bodo najprej zagnani ukazi Header, preden bo nastavljena spremenljivka VERSIONED_FILE.

    Direktive glave so lahko kjer koli, tudi v .htaccess – ni pomembno.

    Samodejno dodajanje različice imenu datoteke na strani HTML

    Kako vstaviti različico v ime skripta, je odvisno od vašega sistema predlog in na splošno od načina dodajanja skriptov (slogi itd.).

    Če na primer uporabljate datum spremembe kot različico in mehanizem predlog Smarty, lahko povezave nastavite takole:

    Funkcija različice doda različico:

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

    Rezultat na strani:

    Optimizacija

    Če se želite izogniti nepotrebnim klicem statistike, lahko shranite matriko s seznamom trenutnih različic v ločeni spremenljivki

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

    V tem primeru se trenutna različica iz matrike preprosto nadomesti v HTML.

    Lahko prekrižate oba pristopa in med razvojem izdelate različico po datumu spremembe - za ustreznost, v produkciji pa različico iz niza za zmogljivost.

    Uporabnost

    Ta metoda predpomnjenja deluje povsod, vključno z Javascriptom, CSS, slikami, filmi Flash itd.

    Uporaben je vsakič, ko se dokument spremeni, vendar mora imeti brskalnik vedno aktualno, posodobljeno različico.

    Predpomnilnik ima pomembno vlogo pri delovanju skoraj vsake spletne aplikacije na ravni dela z bazami podatkov, spletnimi strežniki in tudi na odjemalcu.

    V tem članku bomo poskušali razumeti predpomnjenje odjemalca. Še posebej si bomo ogledali, katere glave HTTP uporabljajo brskalniki in spletni strežniki ter kaj pomenijo.

    Toda najprej ugotovimo, zakaj je predpomnjenje na strani odjemalca sploh potrebno? .

    Spletne strani so sestavljene iz številnih različne elemente: slike, datoteke css in js itd. Nekateri od teh elementov se uporabljajo na več (mnogih) straneh spletnega mesta. Predpomnjenje na strani odjemalca se nanaša na zmožnost brskalnikov, da shranijo kopije datotek (odzive strežnika), da jih ne prenesejo znova. To vam omogoča znatno pospešitev ponovnega nalaganja strani, prihranek prometa in tudi zmanjšanje obremenitve strežnika.

    Obstaja več različnih glav HTTP za nadzor procesov predpomnjenja na strani odjemalca. Pogovorimo se o vsakem od njih.

    Http glave za nadzor odjemalskega predpomnjenja

    Najprej si poglejmo, kako strežnik in brskalnik delujeta brez predpomnjenja. Za jasno razumevanje sem si poskušal predstavljati in vizualizirati proces komunikacije med njimi v obliki besedilnega klepeta. Za nekaj minut si predstavljajte, da sta strežnik in brskalnik oseba, ki si dopisujeta :)

    Brez predpomnilnika (če ni predpomnjenja glav http)

    Kot lahko vidimo, bo brskalnik ob vsakem prikazu slike cat.png znova prenesel s strežnika. Mislim, da ni treba razlagati, da je to počasno in neučinkovito.

    Glava zadnje spremenjenega odgovora in glava zahteve if-Modified-Since.

    Ideja je, da strežnik datoteki (odzivu), ki jo posreduje brskalniku, doda glavo Last-modified.

    Brskalnik zdaj ve, da je bila datoteka ustvarjena (ali spremenjena) 1. decembra 2014. Ko brskalnik naslednjič potrebuje isto datoteko, bo poslal zahtevo z glavo if-Modified-Since.

    Če datoteka ni bila spremenjena, pošlje strežnik brskalniku prazen odgovor s statusom 304 (Ni spremenjeno). V tem primeru brskalnik ve, da datoteka ni bila posodobljena, in lahko prikaže kopijo, ki jo je nazadnje shranil.

    Tako z uporabo Last-modified prihranimo pri nalaganju velika datoteka, s praznim hitrim odzivom strežnika.

    Glava odgovora Etag in glava zahteve If-None-Match.

    Načelo delovanja Etaga je zelo podobno Last-modified, vendar za razliko od njega ni vezan na čas. Čas je relativna stvar.

    Ideja je, da ko je ustvarjena in vsakič, ko se spremeni, strežnik označi datoteko s posebno oznako, imenovano ETag, in ji doda tudi glavo (odgovor), ki jo pošlje brskalniku:

    EToznaka: "686897696a7c876b7e"

    Zdaj brskalnik ve, da ima datoteka trenutne različice oznako ETag, ki je enaka »686897696a7c876b7e«. Ko bo brskalnik naslednjič potreboval isto datoteko, bo poslal zahtevo z glavo If-None-Match: "686897696a7c876b7e" .

    Če se ne ujema: "686897696a7c876b7e"

    Strežnik lahko primerja oznake in, če datoteka ni bila spremenjena, brskalniku pošlje prazen odgovor s statusom 304 (Ni spremenjeno). Kot pri Last-modified bo brskalnik ugotovil, da datoteka ni bila posodobljena, in bo lahko prikazal kopijo iz predpomnilnika.

    Naslov potekel

    Načelo delovanja te glave se razlikuje od zgoraj opisanih Etag in Last-modified. Z možnostjo Expired se določi »datum poteka« (»obdobje ustreznosti«) datoteke. Tisti. Ob prvem nalaganju strežnik sporoči brskalniku, da ne namerava spremeniti datoteke do datuma, določenega v Expired:

    Naslednjič brskalnik, vedoč, da "datum poteka" še ni prišel, ne bo niti poskušal poslati zahteve strežniku in bo prikazal datoteko iz predpomnilnika.

    Ta vrsta predpomnilnika je še posebej pomembna za ilustracije za članke, ikone, favikone, nekatere datoteke css in js itd.

    Glava nadzora predpomnilnika z direktivo max-age.

    Načelo delovanja Cache-control: max-age je zelo podobno Expired. Tu je določen tudi "datum poteka" datoteke, vendar je nastavljen v sekundah in ni vezan na določen čas, kar je v večini primerov veliko bolj priročno.

    Za referenco:

    • 1 dan = 86400 sekund
    • 1 teden = 604800 sekund
    • 1 mesec = 2629000 sekund
    • 1 leto = 31536000 sekund

    Npr.

    Nadzor predpomnilnika: max-age=2629000;

    Glava Cache-control ima poleg max-age še druge direktive. Oglejmo si na hitro najbolj priljubljene:

    javnosti
    Dejstvo je, da lahko zahteve predpomni ne le uporabnikov končni odjemalec (brskalnik), ampak tudi različni vmesni posredniki, omrežja CDN itd. Torej javna direktiva dovoljuje absolutno vsakemu proxy strežniku, da izvaja predpomnjenje tako kot brskalnik.

    zasebno
    Direktiva navaja, da ta datoteka(odziv strežnika) je specifičen za končnega uporabnika in ga ne smejo predpomniti različni vmesni posredniki. Hkrati omogoča predpomnjenje do končnega odjemalca (uporabnikov brskalnik). To je na primer pomembno za notranje strani uporabniškega profila, zahteve znotraj seje itd.

    Omogoča vam, da določite, da mora odjemalec vsakič poslati zahtevo strežniku. Včasih se uporablja z zgoraj opisano glavo Etag.

    brez trgovine
    Stranki daje navodila, da v nobenem primeru ne sme obdržati kopije zahteve ali delov zahteve. To je najstrožja glava, ki preglasi vse predpomnilnike. Izumljen je bil posebej za delo z zaupnimi informacijami.

    obvezno ponovno potrditi
    Ta direktiva naroči brskalniku, naj pošlje obvezno zahtevo strežniku za ponovno potrditev vsebine (na primer, če uporabljate eTag). Dejstvo je, da http v določeni konfiguraciji omogoča predpomnilniku shranjevanje vsebine, ki je že zastarela. must-revalidate zavezuje brskalnik, da pod kakršnimi koli okoliščinami preveri svežost vsebine tako, da pošlje zahtevo strežniku.

    proxy-revalidate
    To je enako kot obvezno ponovno preverjanje, vendar velja le za predpomnjenje posrednikov.

    s-maxage
    Praktično se ne razlikuje od max-age, le da to direktivo upošteva le predpomnilnik različnih proxyjev, ne pa tudi sam uporabnikov brskalnik. Črka “s -” izhaja iz besede “shared” (npr. CDN). Ta direktiva je namenjena posebej CDN-jem in drugim vmesnim predpomnilnikom. Če ga določite, preglasite vrednosti direktive max-age in glave Expired. Če pa ne gradite omrežij CDN, je malo verjetno, da boste kdaj potrebovali s-maxage.

    Kako lahko vidim, katere glave so uporabljene na spletnem mestu?

    Glave zahtev http in glave odgovorov si lahko ogledate v razhroščevalniku vašega priljubljenega brskalnika. Tukaj je primer, kako je videti v Chromu:

    Enako lahko opazimo v vsakem samospoštljivem brskalniku ali http snifferju.

    Nastavitev predpomnjenja v Apache in Nginx

    Dokumentacije za postavitev priljubljenih strežnikov ne bomo ponavljali. Vedno si ga lahko ogledate in. Spodaj bomo podali nekaj primerov iz resničnega življenja, da pokažemo, kako izgledajo konfiguracijske datoteke.

    Primer Konfiguracije Apache za nadzor Poteče

    Določimo različne "roke veljavnosti". različne vrste datoteke. Eno leto za slike, en mesec za skripte, sloge, pdf-je in ikone. Za vse ostalo - 2 dni.

    ExpiresActive On ExpiresByType image/jpg "access plus 1 year" ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/gif "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType text/css "access plus 1 mesec" ExpiresByType aplikacija/pdf "dostop plus 1 mesec" ExpiresByType text/x-javascript "dostop plus 1 mesec" ExpiresByType slika/x-ikona "dostop plus 1 leto" ExpiresDefault "dostop plus 2 dni"

    Primer konfiguracije Nginx za nadzor Expires

    Za različne vrste datotek nastavimo različne "roke veljavnosti". En teden za slike, en dan za sloge in skripte.

    Strežnik ( #... lokacija ~* \.(gif|ico|jpe?g|png)(\?+)?$ ( poteče 1w; ) lokacija ~* \.(css|js)$ ( poteče 1d; ) #... )

    Primer konfiguracije Apache za Cache-control (max-age in public/private/no-cache) Header set Cache-Control "max-age=2592000, public" Header set Cache-Control "max-age=88000, private, must- revalidate" Header set Cache-Control "private, no-store, no-cache, must-revalidate, no-transform, max-age=0" Header set Pragma "no-cache" Primer konfiguracije Nginx za strežnik statičnih datotek Cache-control ( #... lokacija ~* \.(?:ico|css|js|gif|jpe?g|png)$ ( add_header Cache-Control "max-age=88000, javno"; ) #... ) V sklep

    "Predpomnite vse, kar je mogoče predpomniti" je dober moto za spletnega razvijalca. Včasih lahko porabite le nekaj ur za konfiguracijo in hkrati bistveno izboljšate uporabniško izkušnjo vaše strani, znatno zmanjšate obremenitev strežnika in prihranite na prometu. Glavna stvar je, da ne pretiravate in vse pravilno nastavite ob upoštevanju značilnosti vašega vira.

    Pravilno konfigurirano predpomnjenje zagotavlja ogromne prednosti pri zmogljivosti, prihrani pasovno širino in zmanjša stroške strežnika, vendar številna spletna mesta slabo izvajajo predpomnjenje, kar ustvarja pogoje tekmovanja, ki povzročijo, da medsebojno povezani viri postanejo nesinhronizirani.

    Velika večina Najboljše prakse predpomnjenje se nanaša na enega od dveh vzorcev:

    Vzorec št. 1: nespremenljiva vsebina in predpomnilnik dolge največje starosti Cache-Control: max-age=31536000
    • Vsebina URL-ja se ne spremeni, zato ...
    • Brskalnik ali CDN lahko enostavno predpomni vir za eno leto
    • Predpomnjeno vsebino, ki je mlajša od navedene največje starosti, je mogoče uporabiti brez posvetovanja s strežnikom

    Stran: Hej, potrebujem "/script-v1.js", "/styles-v1.css" in "/cats-v1.jpg" 10:24

    Cash: Jaz sem prazen, kaj pa ti, Server? 10:24

    Strežnik: OK, tukaj so. Mimogrede, Cash, jih je treba uporabljati eno leto, ne več. 10:25

    Cash: Hvala! 10:25

    Stran: Hura! 10:25

    Naslednji dan

    Stran: Hej, potrebujem "/script-v2 .js", "/styles-v2 .css" in "/cats-v1.jpg" 08:14

    Gotovina: Slika z mačkami je, ostalo pa ne. strežnik? 08:14

    Strežnik: Enostavno – tukaj sta nova CSS in JS. Še enkrat, gotovina: njihov rok trajanja ni daljši od enega leta. 08:15

    Gotovina: Super! 08:15

    Stran: Hvala! 08:15

    Cash: Hmm, že kar nekaj časa nisem uporabljal "/script-v1.js" & "/styles-v1.css". Čas je, da jih odstranimo. 12:32

    Z uporabo tega vzorca nikoli ne spremenite vsebine določenega URL-ja, ampak spremenite sam URL:

    Vsak URL ima nekaj, kar se spreminja skupaj z vsebino. To je lahko številka različice, spremenjeni datum ali zgoščena vrednost vsebine (kar sem izbral za svoj blog).

    Večina ogrodij na strani strežnika ima orodja, ki vam omogočajo, da z lahkoto počnete takšne stvari (v Djangu uporabljam Manifest​Static​Files​Storage); V Node.js so tudi zelo majhne knjižnice, ki rešujejo enake težave, na primer gulp-rev.

    Vendar ta vzorec ni primeren za stvari, kot so članki in objave v spletnih dnevnikih. Njihovim URL-jem ni mogoče določiti različic in njihova vsebina se lahko spremeni. Resno, pogosto imam slovnične in ločilne napake in moram biti sposoben hitro posodobiti vsebino.

    Vzorec #2: spremenljiva vsebina, ki je vedno potrjena na strežniku Nadzor predpomnilnika: brez predpomnilnika
    • Vsebina URL-ja se bo spremenila, kar pomeni ...
    • Nobene lokalno predpomnjene različice ni mogoče uporabiti brez navedbe strežnika.

    Stran: Hej, potrebujem vsebino "/about/" in "/sw.js" 11:32

    Cash: Ne morem ti pomagati. strežnik? 11:32

    Strežnik: Nekaj ​​jih je. Gotovina, imejte jih pri sebi, vendar me vprašajte, preden jih uporabite. 11:33

    Gotovina: Točno tako! 11:33

    Stran: Hvala! 11:33

    Naslednji dan

    Stran: Hej, spet potrebujem vsebino "/about/" in "/sw.js" 09:46

    Gotovina: Samo minuto. Strežnik, ali so moje kopije v redu? Kopija »/about/« je od ponedeljka, »/sw.js« pa od včeraj. 09:46

    Strežnik: "/sw.js" se ni spremenil ... 09:47

    Gotovina: kul. Stran, obdržite "/sw.js" . 09:47

    Strežnik: ...vendar imam »/o/« nova različica. Cash, pridrži, ampak kot zadnjič me ne pozabi najprej vprašati. 09:47

    Cash: Razumem! 09:47

    Stran: Odlično! 09:47

    Opomba: brez predpomnilnika ne pomeni "ne predpomniti", ampak pomeni "preveriti" (ali ponovno potrditi) predpomnjeni vir na strežniku. In no-store pove brskalniku, naj sploh ne predpomni. Poleg tega obvezno ponovno preverjanje ne pomeni obveznega preverjanja, ampak da se predpomnjeni vir uporablja le, če je mlajši od navedene največje starosti, in le v nasprotnem primeru se ponovno preveri. Tako se je vse začelo ključne besede za predpomnjenje.

    V tem vzorcu lahko odgovoru dodamo ETag (ID različice po vaši izbiri) ali glavo Last-Modified. Ko odjemalec naslednjič zahteva vsebino, se izpiše If-None-Match oziroma If-Modified-Since, kar strežniku omogoči, da reče »Uporabi, kar imaš, tvoj predpomnilnik je posodobljen,« tj. vrne HTTP 304.

    Če pošiljanje ETag / Last-Modified ni mogoče, strežnik vedno pošlje celotno vsebino.

    Ta vzorec vedno zahteva omrežne klice, zato ni tako dober kot prvi vzorec, ki zmore brez omrežnih zahtev.

    Ni nenavadno, da nimamo infrastrukture za prvi vzorec, lahko pa se pojavijo tudi težave z omrežnimi zahtevami v vzorcu 2. Posledično se uporabi vmesna možnost: kratka največja starost in spremenljiva vsebina. To je slab kompromis.

    Uporaba max-age s spremenljivo vsebino je na splošno napačna izbira

    In na žalost je to pogosto; primer so strani Github.

    Predstavljajte si:

    • /Članek/
    • /styles.css
    • /script.js

    Z glavo strežnika:

    Nadzor predpomnilnika: obvezno ponovno preverjanje, največja starost=600

    • Spremembe vsebine URL-ja
    • Če ima brskalnik predpomnjeno različico, starejšo od 10 minut, se ta uporabi brez posvetovanja s strežnikom
    • Če takega predpomnilnika ni, se uporabi omrežna zahteva, če je mogoče z If-Modified-Since ali If-None-Match

    Stran: Hej, potrebujem "/article/", "/script.js" in "/styles.css" 10:21

    Cash: Nimam ničesar, kot ti, Server? 10:21

    Strežnik: Ni problema, tukaj so. Toda zapomni si, gotovina: uporabiti jih je mogoče v naslednjih 10 minutah. 10:22

    Gotovina: Da! 10:22

    Stran: Hvala! 10:22

    Stran: Hej, spet potrebujem "/article/", "/script.js" in "/styles.css" 10:28

    Cash: Ups, žal mi je, izgubil sem "/styles.css", vendar imam vse ostalo, izvolite. Strežnik, ali mi lahko prilagodite "/styles.css"? 10:28

    Strežnik: Počasi, spremenil se je že od zadnjega, ko si ga vzel. Naslednjih 10 minut ga lahko varno uporabljate. 10:29

    Gotovina: Ni problema. 10:29

    Stran: Hvala! A zdi se, da je šlo nekaj narobe! Vse je pokvarjeno! Kaj se dogaja? 10:29

    Ta vzorec ima med testiranjem pravico do življenja, vendar v resničnem projektu pokvari vse in mu je zelo težko slediti. V zgornjem primeru je strežnik posodobil HTML, CSS in JS, vendar je stran upodobljena s starim predpomnjenim HTML in JS ter posodobljenim CSS iz strežnika. Neujemanje različic vse uniči.

    Ko bistveno spremenimo HTML, pogosto spremenimo tako CSS, da pravilno odraža novo strukturo, kot JavaScript, da sledimo vsebini in slogu. Vsi ti viri so neodvisni, vendar glave predpomnjenja tega ne morejo izraziti. Posledično se lahko uporabniki znajdejo Najnovejša različica en/dva vira in stara različica ostalih.

    max-age je nastavljen glede na odzivni čas, tako da bodo vsi viri, če so preneseni kot del enega naslova, potekli hkrati, vendar še vedno obstaja majhna možnost desinhronizacije. Če imate strani, ki ne vključujejo JavaScripta ali vključujejo druge sloge, njihovi datumi poteka predpomnilnika ne bodo sinhronizirani. In kar je še huje, brskalnik nenehno vleče vsebino iz predpomnilnika, ne da bi vedel, da so HTML, CSS in JS medsebojno odvisni, tako da lahko z veseljem potegne eno stvar s seznama in pozabi na vse ostalo. Če upoštevamo vse te dejavnike skupaj, morate razumeti, da je verjetnost neujemajočih se različic precej velika.

    Za uporabnika je lahko rezultat pokvarjena postavitev strani ali druge težave. Od majhnih napak do popolnoma neuporabne vsebine.

    Na srečo imajo uporabniki izhod v sili ...

    Včasih pomaga osvežitev strani

    Če se stran naloži z osvežitvijo, brskalniki vedno izvedejo ponovno preverjanje na strani strežnika, ne upoštevajo max-age. Torej, če ima uporabnik kaj pokvarjeno zaradi max-age, lahko preprosta osvežitev strani vse popravi. Seveda pa bo po najdbi žlic še vedno ostala usedlina in odnos do vaše strani bo nekoliko drugačen.

    Storitveni delavec lahko podaljša življenjsko dobo teh hroščev

    Na primer, imate storitvenega delavca, kot je ta:

    Različica Const = "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 predpomnilnike ... )); self.addEventListener("fetch", event => ( event.respondWith(caches.match(event.request) .then(response => response || fetch(event.request))); ));

    Ta serviser:

    • predpomni skript in sloge
    • uporablja predpomnilnik, če obstaja ujemanje, sicer dostopa do omrežja

    Če spremenimo CSS/JS, povečamo tudi številko različice, kar sproži posodobitev. Ker pa addAll najprej dostopa do predpomnilnika, lahko pridemo v stanje tekmovanja zaradi največje starosti in neujemajočih se različic CSS & JS.

    Ko so predpomnjeni, bomo imeli nezdružljive CSS & JS do naslednje posodobitve storitvenega delavca - in to je, razen če med posodobitvijo ponovno pridemo v stanje tekmovanja.

    Predpomnjenje v servisnem delavcu lahko preskočite:

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

    Na žalost možnosti za predpomnjenje niso podprte v Chromu/Operi in so bile pravkar dodane v nočno gradnjo Firefoxa, vendar lahko to storite sami:

    Self.addEventListener("install", event => ( event.waitUntil(caches.open(`static-$(version)`) .then(cache => Promise.all([ "/styles.css", "/script .js" ].map(url => ( // prekinitev predpomnilnika z uporabo naključnega poizvedbenega niza return fetch(`$(url)?$(Math.random())`).then(response => ( // neuspeh na 404, 500 itd. if (!response.ok) throw Error("Not ok"); return cache.put(url, response); )) ))))); ));

    V tem primeru ponastavim predpomnilnik z uporabo naključnega števila, vendar lahko greste še dlje in med gradnjo dodate zgoščeno vrednost vsebine (to je podobno temu, kar počne sw-precache). To je nekakšna implementacija prvega vzorca z uporabo JavaScripta, vendar deluje samo s servisnim delavcem, ne z brskalniki in CDN.

    Storitveni delavci in predpomnilnik HTTP odlično delujejo skupaj, ne sili jih v prepir!

    Kot lahko vidite, lahko odpravite napake predpomnjenja v vašem servisnem delavcu, vendar je bolje, da rešite koren težave. Pravilna nastavitev predpomnjenje ne le olajša delo storitvenega delavca, ampak tudi pomaga brskalnikom, ki ne podpirajo storitvenih delavcev (Safari, IE/Edge), in vam tudi omogoča, da kar najbolje izkoristite svoj CDN.

    Pravilne glave predpomnjenja lahko tudi olajšajo posodabljanje storitvenega delavca.

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

    Tukaj sem predpomnil korensko stran z vzorcem št. 2 (ponovno preverjanje na strani strežnika) in vse druge vire z vzorcem št. 1 (nespremenljiva vsebina). Vsaka posodobitev storitvenega delavca bo povzročila zahtevo za korensko stran, vsi drugi viri pa bodo naloženi samo, če se je njihov URL spremenil. To je dobro, ker prihrani promet in izboljša delovanje, ne glede na to, ali nadgrajujete s prejšnjega ali zelo stara različica.

    Tukaj je pomembna prednost pred domačo izvedbo, ko se celotna dvojiška datoteka prenese tudi z majhno spremembo ali povzroči zapleteno primerjavo binarne datoteke. Tako lahko posodobimo veliko spletno aplikacijo z relativno majhno obremenitvijo.

    Storitveni delavci delujejo bolje kot izboljšava kot začasna bergla, zato delajte s predpomnilnikom, namesto da se borite z njim.

    Ob previdni uporabi sta lahko največja starost in spremenljiva vsebnost zelo dobri

    max-age je zelo pogosto napačna izbira za spremenljivo vsebino, vendar ne vedno. Na primer, izvirni članek ima največjo starost tri minute. Pogoj tekmovanja ni problem, saj ni odvisnosti od strani, ki uporablja isti vzorec predpomnjenja (CSS, JS in slike uporabljajo vzorec #1 - nespremenljiva vsebina), vse ostalo ne uporablja tega vzorca.

    Ta vzorec pomeni, da lahko udobno napišem priljubljen članek in da lahko moj CDN (Cloudflare) razbremeni strežnik, če sem pripravljen počakati tri minute, da posodobljeni članek postane na voljo. dostopen uporabnikom.

    Ta vzorec je treba uporabljati brez fanatizma. Če sem članku dodal nov razdelek in se nanj povezal iz drugega članka, sem ustvaril odvisnost, ki jo je treba razrešiti. Uporabnik lahko klikne na povezavo in dobi kopijo članka brez želenega razdelka. Če se želim temu izogniti, bi moral osvežiti članek, izbrisati predpomnjeno različico članka iz Cloudflare, počakati tri minute in šele nato dodati povezavo do drugega članka. Da, ta vzorec zahteva previdnost.

    Ob pravilni uporabi predpomnjenje zagotavlja znatne izboljšave zmogljivosti in prihranek pasovne širine. Postrezite nespremenljivo vsebino, če lahko preprosto spremenite URL, ali uporabite ponovno preverjanje na strani strežnika. Zmešajte največjo starost in spremenljivo vsebino, če ste dovolj pogumni in prepričani, da vaša vsebina nima odvisnosti, ki bi se lahko izognile sinhronizaciji.

    Pri spreminjanju spletnih strani se pogosto srečamo s tem, da se vsebine strani, css datoteke in skripte (.js) brskalnik shranijo v predpomnilnik in ostanejo nespremenjene precej dolgo časa. To vodi k dejstvu, da je treba odjemalce navaditi na zapletene kombinacije F5 ali Ctrl + F5, da se spremembe odražajo v vseh brskalnikih. In od časa do časa se prepričajte, da so pritisnjeni.

    Postopek je precej dolgočasen in neprijeten. Seveda se lahko rešite iz situacije tako, da vsakič preimenujete datoteke, vendar je spet neprijetno.

    Vendar pa obstaja način, ki nam bo omogočil, da ostanemo z istimi imeni in ponastavimo predpomnjenje datotek .css ali .js v trenutku, ko ga potrebujemo. In za vedno pozabite na Ctrl + F5.

    Bistvo je, da bomo našim datotekam .css ali .js na koncu dodali psevdoparameter, ki ga bomo občasno spremenili in s tem ponastavili predpomnilnik v brskalniku.

    Tako vstop v izvorna koda zdaj bo videti takole:

    Kjer je 186485 poljubna kombinacija, ki izpiše isto datoteko, vendar jo brskalnik zahvaljujoč psevdoparametru interpretira kot novo ?186485

    Zdaj, da ne bi vsakič spreminjali vseh pojavitev našega parametra, ga bomo nastavili v datoteki php, ki jo bomo povezali na vsa mesta, ki jih potrebujemo: