Įsisavinkite pažangias Fetch API technikas: užklausų perėmimą modifikavimui ir atsakymų kaupimą optimaliam našumui. Sužinokite geriausias praktikas globalioms programoms.
Pažangus Fetch API: užklausų perėmimas ir atsakymų kaupimas
„Fetch“ API tapo standartu tinklo užklausoms šiuolaikiniame „JavaScript“. Nors pagrindinis naudojimas yra paprastas, norint atskleisti visą jo potencialą, reikia suprasti pažangias technikas, tokias kaip užklausų perėmimas ir atsakymų kaupimas (angl. caching). Šiame straipsnyje išsamiai nagrinėsime šias koncepcijas, pateiksime praktinių pavyzdžių ir geriausių praktikų, kaip kurti našias, visame pasaulyje prieinamas interneto programas.
„Fetch“ API supratimas
„Fetch“ API suteikia galingą ir lanksčią sąsają resursų gavimui tinkle. Jis naudoja „Promises“ (pažadus), todėl asinchroniškas operacijas lengviau valdyti ir suprasti. Prieš gilinantis į pažangias temas, trumpai apžvelkime pagrindus:
Pagrindinis „Fetch“ naudojimas
Paprasta „Fetch“ užklausa atrodo taip:
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Data:', data);
})
.catch(error => {
console.error('Fetch error:', error);
});
Šis kodas gauna duomenis iš nurodyto URL, tikrina HTTP klaidas, apdoroja atsakymą kaip JSON ir išveda duomenis į konsolę. Klaidų apdorojimas yra labai svarbus, siekiant užtikrinti patikimą programos veikimą.
Užklausų perėmimas
Užklausų perėmimas apima tinklo užklausų modifikavimą arba stebėjimą prieš jas išsiunčiant į serverį. Tai gali būti naudinga įvairiems tikslams, įskaitant:
- Autentifikavimo antraščių pridėjimas
- Užklausos duomenų transformavimas
- Užklausų registravimas derinimo tikslais
- API atsakymų imitavimas kūrimo metu
Užklausų perėmimas paprastai atliekamas naudojant „Service Worker“, kuris veikia kaip tarpininkas (proxy) tarp interneto programos ir tinklo.
„Service Workers“: perėmimo pagrindas
„Service Worker“ yra „JavaScript“ failas, veikiantis fone, atskirai nuo pagrindinės naršyklės gijos. Jis gali perimti tinklo užklausas, kaupti atsakymus ir suteikti funkcionalumą neprisijungus. Norėdami naudoti „Service Worker“, pirmiausia turite jį užregistruoti:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
Šis kodas patikrina, ar naršyklė palaiko „Service Workers“, ir užregistruoja service-worker.js
failą. Aprėptis (scope) apibrėžia, kuriuos URL adresus valdys „Service Worker“.
Užklausų perėmimo įgyvendinimas
service-worker.js
faile galite perimti užklausas naudodami fetch
įvykį:
self.addEventListener('fetch', event => {
// Intercept all fetch requests
event.respondWith(
new Promise(resolve => {
// Clone the request to avoid modifying the original
const req = event.request.clone();
// Modify the request (e.g., add an authentication header)
const headers = new Headers(req.headers);
headers.append('Authorization', 'Bearer your_api_key');
const modifiedReq = new Request(req.url, {
method: req.method,
headers: headers,
body: req.body,
mode: 'cors',
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
integrity: req.integrity
});
// Make the modified request
fetch(modifiedReq)
.then(response => resolve(response))
.catch(error => {
console.error('Fetch error in Service Worker:', error);
// Optionally, return a default response or error page
resolve(new Response('Offline', { status: 503, statusText: 'Service Unavailable' }));
});
})
);
});
Šis kodas perima kiekvieną fetch
užklausą, ją klonuoja, prideda Authorization
antraštę ir tada atlieka modifikuotą užklausą. Metodas event.respondWith()
nurodo naršyklei, kaip apdoroti užklausą. Būtina klonuoti užklausą; kitaip modifikuosite originalią užklausą, o tai gali sukelti netikėtą elgesį. Taip pat užtikrinama, kad visos pradinės užklausos parinktys būtų perduotos, siekiant suderinamumo. Atkreipkite dėmesį į klaidų apdorojimą: svarbu numatyti atsarginį variantą, jei „fetch“ nepavyktų (pvz., neprisijungus).
Pavyzdys: autentifikavimo antraščių pridėjimas
Dažnas užklausų perėmimo panaudojimo atvejis yra autentifikavimo antraščių pridėjimas prie API užklausų. Tai užtikrina, kad tik autorizuoti vartotojai gali pasiekti apsaugotus resursus.
self.addEventListener('fetch', event => {
if (event.request.url.startsWith('https://api.example.com')) {
event.respondWith(
new Promise(resolve => {
const req = event.request.clone();
const headers = new Headers(req.headers);
// Replace with actual authentication logic (e.g., retrieving token from local storage)
const token = localStorage.getItem('api_token');
if (token) {
headers.append('Authorization', `Bearer ${token}`);
} else {
console.warn("No API token found, request may fail.");
}
const modifiedReq = new Request(req.url, {
method: req.method,
headers: headers,
body: req.body,
mode: 'cors',
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
integrity: req.integrity
});
fetch(modifiedReq)
.then(response => resolve(response))
.catch(error => {
console.error('Fetch error in Service Worker:', error);
resolve(new Response('Offline', { status: 503, statusText: 'Service Unavailable' }));
});
})
);
} else {
// Let the browser handle the request as usual
event.respondWith(fetch(event.request));
}
});
Šis kodas prideda Authorization
antraštę užklausoms, kurios prasideda https://api.example.com
. Jis gauna API raktą iš vietinės saugyklos (local storage). Būtina įgyvendinti tinkamą raktų valdymą ir saugumo priemones, tokias kaip HTTPS ir saugi saugykla.
Pavyzdys: užklausos duomenų transformavimas
Užklausų perėmimas taip pat gali būti naudojamas transformuoti užklausos duomenis prieš juos išsiunčiant į serverį. Pavyzdžiui, galbūt norėsite konvertuoti duomenis į konkretų formatą arba pridėti papildomų parametrų.
self.addEventListener('fetch', event => {
if (event.request.url.includes('/submit-form')) {
event.respondWith(
new Promise(resolve => {
const req = event.request.clone();
req.text().then(body => {
try {
const parsedBody = JSON.parse(body);
// Transform the data (e.g., add a timestamp)
parsedBody.timestamp = new Date().toISOString();
// Convert the transformed data back to JSON
const transformedBody = JSON.stringify(parsedBody);
const modifiedReq = new Request(req.url, {
method: req.method,
headers: req.headers,
body: transformedBody,
mode: 'cors',
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
integrity: req.integrity
});
fetch(modifiedReq)
.then(response => resolve(response))
.catch(error => {
console.error('Fetch error in Service Worker:', error);
resolve(new Response('Offline', { status: 503, statusText: 'Service Unavailable' }));
});
} catch (error) {
console.error("Error parsing request body:", error);
resolve(fetch(event.request)); // Fallback to original request
}
});
})
);
} else {
event.respondWith(fetch(event.request));
}
});
Šis kodas perima užklausas į /submit-form
, apdoroja užklausos turinį kaip JSON, prideda laiko žymę ir tada siunčia transformuotus duomenis į serverį. Klaidų apdorojimas yra būtinas, siekiant užtikrinti, kad programa nesugriūtų, jei užklausos turinys nėra galiojantis JSON.
Atsakymų kaupimas (caching)
Atsakymų kaupimas apima API užklausų atsakymų saugojimą naršyklės spartinančiojoje atmintyje (cache). Tai gali žymiai pagerinti našumą, sumažinant tinklo užklausų skaičių. Kai yra prieinamas sukauptas atsakymas, naršyklė gali jį pateikti tiesiai iš atminties, nereikalaudama naujos užklausos į serverį.
Atsakymų kaupimo privalumai
- Geresnis našumas: greitesnis įkėlimo laikas ir jautresnė vartotojo patirtis.
- Sumažėjęs pralaidumo naudojimas: mažiau duomenų perduodama per tinklą, taupant pralaidumą tiek vartotojui, tiek serveriui.
- Funkcionalumas neprisijungus: sukaupti atsakymai gali būti pateikiami net tada, kai vartotojas yra neprisijungęs, užtikrinant sklandžią patirtį.
- Kaštų taupymas: mažesnis pralaidumo naudojimas reiškia mažesnes išlaidas tiek vartotojams, tiek paslaugų teikėjams, ypač regionuose, kur duomenų planai yra brangūs ar riboti.
Atsakymų kaupimo įgyvendinimas su „Service Workers“
„Service Workers“ suteikia galingą mechanizmą atsakymų kaupimui įgyvendinti. Galite naudoti Cache
API atsakymams saugoti ir gauti.
const cacheName = 'my-app-cache-v1';
const cacheableUrls = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'https://api.example.com/data'
];
// Install event: Cache static assets
self.addEventListener('install', event => {
event.waitUntil(
caches.open(cacheName)
.then(cache => {
console.log('Caching app shell');
return cache.addAll(cacheableUrls);
})
);
});
// Activate event: Clean up old caches
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(name => name !== cacheName)
.map(name => caches.delete(name))
);
})
);
});
// Fetch event: Serve cached responses or fetch from the network
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Cache hit - return response
if (response) {
return response;
}
// Not in cache - fetch from network
return fetch(event.request).then(
response => {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response (because it's a stream and can only be consumed once)
const responseToCache = response.clone();
caches.open(cacheName)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
}
).catch(error => {
// Handle network error
console.error("Fetch failed:", error);
// Optionally, provide a fallback response (e.g., offline page)
return caches.match('/offline.html');
});
})
);
});
Šis kodas kaupia statinius resursus diegimo (install) įvykio metu ir pateikia sukauptus atsakymus „fetch“ įvykio metu. Jei atsakymas nerandamas kaupykloje, jis gaunamas iš tinklo, kaupiamas ir tada grąžinamas. activate
įvykis naudojamas senoms kaupykloms išvalyti, kai „Service Worker“ yra atnaujinamas. Šis metodas taip pat užtikrina, kad būtų kaupiami tik galiojantys atsakymai (statusas 200 ir tipas 'basic').
Kaupimo strategijos
Yra keletas skirtingų kaupimo strategijų, kurias galite naudoti, priklausomai nuo jūsų programos poreikių:
- Pirmiausia kaupykla (Cache-First): pirmiausia bandoma pateikti atsakymą iš kaupyklos. Jei jis nerandamas, gaunamas iš tinklo ir kaupiamas. Tai tinka statiniams resursams ir retai besikeičiantiems ištekliams.
- Pirmiausia tinklas (Network-First): pirmiausia bandoma gauti atsakymą iš tinklo. Jei nepavyksta, pateikiamas iš kaupyklos. Tai tinka dinamiškiems duomenims, kurie turi būti aktualūs.
- Kaupykla, tada tinklas (Cache, then Network): atsakymas pateikiamas nedelsiant iš kaupyklos, o tada kaupykla atnaujinama naujausia versija iš tinklo. Tai užtikrina greitą pradinį įkėlimą ir garantuoja, kad vartotojas galiausiai visada turės naujausius duomenis.
- Pasenęs, kol atnaujinama (Stale-While-Revalidate): nedelsiant grąžinamas sukauptas atsakymas, tuo pačiu metu tikrinant tinklą dėl atnaujintos versijos. Kaupykla atnaujinama fone, jei yra naujesnė versija. Panašu į „Kaupykla, tada tinklas“, bet suteikia sklandesnę vartotojo patirtį.
Kaupimo strategijos pasirinkimas priklauso nuo konkrečių jūsų programos reikalavimų. Atsižvelkite į tokius veiksnius kaip atnaujinimų dažnumas, duomenų naujumo svarba ir turimas pralaidumas.
Pavyzdys: API atsakymų kaupimas
Štai API atsakymų kaupimo pavyzdys, naudojant „Pirmiausia kaupykla“ strategiją:
self.addEventListener('fetch', event => {
if (event.request.url.startsWith('https://api.example.com')) {
event.respondWith(
caches.match(event.request)
.then(response => {
// Cache hit - return response
if (response) {
return response;
}
// Not in cache - fetch from network
return fetch(event.request).then(
response => {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response (because it's a stream and can only be consumed once)
const responseToCache = response.clone();
caches.open(cacheName)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
} else {
// Let the browser handle the request as usual
event.respondWith(fetch(event.request));
}
});
Šis kodas kaupia API atsakymus iš https://api.example.com
. Kai pateikiama užklausa, „Service Worker“ pirmiausia patikrina, ar atsakymas jau yra kaupykloje. Jei taip, grąžinamas sukauptas atsakymas. Jei ne, užklausa siunčiama į tinklą, o atsakymas yra kaupiamas prieš jį grąžinant.
Pažangūs aspektai
Kaupyklos anuliavimas (invalidation)
Vienas didžiausių iššūkių dirbant su kaupimu yra kaupyklos anuliavimas. Kai duomenys serveryje pasikeičia, turite užtikrinti, kad kaupykla būtų atnaujinta. Yra keletas kaupyklos anuliavimo strategijų:
- Kaupyklos „pramušimas“ (Cache Busting): pridėkite versijos numerį arba laiko žymę prie resurso URL. Kai resursas pasikeičia, pasikeičia ir URL, todėl naršyklė atsisiųs naują versiją.
- Galiojimas pagal laiką: nustatykite maksimalų sukauptų atsakymų amžių. Pasibaigus galiojimo laikui, naršyklė gaus naują versiją iš serverio. Naudokite
Cache-Control
antraštę, kad nurodytumėte maksimalų amžių. - Rankinis anuliavimas: naudokite
caches.delete()
metodą, kad rankiniu būdu pašalintumėte sukauptus atsakymus. Tai gali būti inicijuota serverio įvykio arba vartotojo veiksmo. - „WebSockets“ realaus laiko atnaujinimams: naudokite „WebSockets“ atnaujinimams iš serverio siųsti klientui, prireikus anuliuojant kaupyklą.
Turinio pristatymo tinklai (CDN)
Turinio pristatymo tinklai (CDN) yra paskirstyti serverių tinklai, kurie kaupia turinį arčiau vartotojų. CDN naudojimas gali žymiai pagerinti našumą vartotojams visame pasaulyje, sumažindamas delsą ir pralaidumo suvartojimą. Populiarūs CDN tiekėjai yra „Cloudflare“, „Amazon CloudFront“ ir „Akamai“. Integruojant su CDN, įsitikinkite, kad Cache-Control
antraštės yra teisingai sukonfigūruotos optimaliam kaupimo elgesiui.
Saugumo aspektai
Įgyvendinant užklausų perėmimą ir atsakymų kaupimą, būtina atsižvelgti į saugumo pasekmes:
- HTTPS: visada naudokite HTTPS, kad apsaugotumėte perduodamus duomenis.
- CORS: teisingai konfigūruokite „Cross-Origin Resource Sharing“ (CORS), kad išvengtumėte neteisėtos prieigos prie resursų.
- Duomenų valymas: išvalykite vartotojo įvestį, kad išvengtumėte tarp svetainių scenarijų (XSS) atakų.
- Saugi saugykla: saugokite jautrius duomenis, tokius kaip API raktai ir prieigos raktai, saugiai (pvz., naudojant tik HTTPS slapukus ar saugios saugyklos API).
- Subresursų vientisumas (SRI): naudokite SRI, kad užtikrintumėte, jog iš trečiųjų šalių CDN gauti resursai nebuvo pakeisti.
„Service Workers“ derinimas
„Service Workers“ derinimas gali būti sudėtingas, tačiau naršyklės kūrėjo įrankiai siūlo keletą funkcijų, kurios gali padėti:
- „Application“ skirtukas: „Chrome DevTools“ skirtukas „Application“ suteikia informacijos apie „Service Workers“, įskaitant jų būseną, aprėptį ir kaupyklos saugyklą.
- Konsolės registravimas: naudokite
console.log()
teiginius informacijai apie „Service Worker“ veiklą registruoti. - Stabdymo taškai (Breakpoints): nustatykite stabdymo taškus „Service Worker“ kode, kad galėtumėte žingsnis po žingsnio sekti vykdymą ir tikrinti kintamuosius.
- Atnaujinti perkrovus: „Application“ skirtuke įjunkite parinktį „Update on reload“, kad užtikrintumėte, jog „Service Worker“ būtų atnaujintas kiekvieną kartą perkrovus puslapį.
- Išregistruoti „Service Worker“: „Application“ skirtuke naudokite mygtuką „Unregister“, kad išregistruotumėte „Service Worker“. Tai gali būti naudinga sprendžiant problemas arba pradedant iš naujo.
Išvada
Užklausų perėmimas ir atsakymų kaupimas yra galingos technikos, galinčios žymiai pagerinti interneto programų našumą ir vartotojo patirtį. Naudodami „Service Workers“, galite perimti tinklo užklausas, prireikus jas modifikuoti ir kaupti atsakymus, kad užtikrintumėte funkcionalumą neprisijungus ir greitesnį įkėlimo laiką. Teisingai įgyvendintos, šios technikos gali padėti jums sukurti našias, visame pasaulyje prieinamas interneto programas, kurios suteikia sklandžią vartotojo patirtį net ir sudėtingomis tinklo sąlygomis. Įgyvendindami šias technikas, atsižvelkite į įvairias tinklo sąlygas ir duomenų kainas, su kuriomis susiduria vartotojai visame pasaulyje, kad užtikrintumėte optimalų prieinamumą ir įtrauktį. Visada teikite pirmenybę saugumui, kad apsaugotumėte jautrius duomenis ir išvengtumėte pažeidžiamumų.
Įvaldę šias pažangias „Fetch“ API technikas, galite pakelti savo interneto svetainių kūrimo įgūdžius į kitą lygį ir kurti išties išskirtines interneto programas.