JavaScript umà posÃlat sÃÅ¥ové požadavky na server a naÄÃtat nové informace, kdykoli jsou zapotÅebÃ.
Můžeme napÅÃklad použÃt sÃÅ¥ový požadavek k:
- odeslánà objednávky,
- naÄtenà informacà o uživateli,
- staženà poslednÃch aktualizacà ze serveru,
- â¦atd.
â¦A to vÅ¡echno je možné bez znovunaÄtenà stránky!
Pro sÃÅ¥ové požadavky z JavaScriptu se použÃvá zastÅeÅ¡ujÃcà pojem âAJAXâ (zkratka z Asynchronous JavaScript And XML â âAsynchronnà JavaScript a XMLâ). NemusÃme vÅ¡ak použÃvat XML: tento pojem pocházà z dÅÃvÄjšà doby, proto se tam toto slovo vyskytuje. Možná jste tento pojem už slyÅ¡eli.
Poslat sÃÅ¥ový požadavek a zÃskat informace ze serveru je možné mnoha způsoby.
Metoda fetch() je modernà a vÃceúÄelová, proto zaÄneme s nÃ. Nenà podporována ve starých prohlÞeÄÃch (lze použÃt polyfill), ale v modernÃch je podporována velmi dobÅe.
Jejà základnà syntaxe je:
let pÅÃslib = fetch(url, [volby])
urlâ URL, z nÞ se má stahovat.volbyâ nepovinné volby: metoda, hlaviÄky atd.
Bez objektu volby je to jednoduchý požadavek GET, který stáhne obsah adresy url.
ProhlÞeÄ zaÄne tento požadavek ihned plnit a vrátà pÅÃslib, který by mÄl volajÃcà kód použÃt k zÃskánà výsledku.
ZÃskánà odpovÄdi je obvykle dvoufázový proces.
V prvnà fázi se pÅÃslib, vrácený metodou fetch, splnà s objektem zabudované tÅÃdy Response hned, jakmile server poÅ¡le hlaviÄky odpovÄdi.
V této fázi můžeme zkontrolovat HTTP status, abychom vidÄli, zda požadavek byl úspÄÅ¡ný nebo ne, zkontrolovat hlaviÄky, ale tÄlo jeÅ¡tÄ nemáme.
PÅÃslib je zamÃtnut, jestliže metoda fetch nedokázala tento HTTP požadavek vytvoÅit, napÅ. kvůli sÃÅ¥ovým problémům, nebo když zadané webové sÃdlo neexistuje. Abnormálnà HTTP statusy, napÅ. 404 nebo 500, chybu nevyvolajÃ.
HTTP status vidÃme ve vlastnostech odpovÄdi:
statusâ kód HTTP statusu, napÅ. 200.okâ boolean,true, pokud kód HTTP statusu je 200-299.
PÅÃklad:
let odpovÄÄ = await fetch(url);
if (odpovÄÄ.ok) { // pokud HTTP status je 200-299
// zÃskáme tÄlo odpovÄdi (metodou vysvÄtlenou dále)
let json = await odpovÄÄ.json();
} else {
alert("HTTP chyba: " + odpovÄÄ.status);
}
Abychom ve druhé fázi zÃskali tÄlo odpovÄdi, musÃme volat dalšà metodu.
Response poskytuje nÄkolik metod založených na pÅÃslibech, které sloužà k pÅÃstupu k tÄlu v různých formátech:
response.text()â naÄte odpovÄÄ a vrátà ji jako text,response.json()â rozparsuje odpovÄÄ ve formátu JSON,response.formData()â vrátà odpovÄÄ jako objektFormData(bude vysvÄtleno v pÅÃÅ¡tà kapitole),response.blob()â vrátà odpovÄÄ jako blob (binárnà data s typem),response.arrayBuffer()â vrátà odpovÄÄ jako ArrayBuffer (nÃzkoúrovÅová reprezentace binárnÃch dat),- kromÄ toho
response.bodyje objekt tÅÃdy ReadableStream, který umožÅuje naÄtenà tÄla po Äástech, pÅÃklad uvidÃme pozdÄji.
NapÅÃklad zÃskejme objekt JSON s poslednÃmi pÅÃspÄvky z GitHubu:
let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
let odpovÄÄ = await fetch(url);
let pÅÃspÄvky = await odpovÄÄ.json(); // naÄteme tÄlo odpovÄdi a parsujeme je jako JSON
alert(pÅÃspÄvky[0].author.login);
Nebo totéž bez await za použità ÄistÄ pÅÃslibové syntaxe:
fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits')
.then(odpovÄÄ => odpovÄÄ.json())
.then(pÅÃspÄvky => alert(pÅÃspÄvky[0].author.login));
K zÃskánà odpovÄdi v textové podobÄ použijeme await odpovÄÄ.text() mÃsto .json():
let odpovÄÄ = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
let text = await odpovÄÄ.text(); // naÄteme tÄlo odpovÄdi jako text
alert(text.slice(0, 80) + '...');
Pro ukázku naÄÃtánà v binárnÃm formátu naÄteme a zobrazÃme obrázek s logem specifikace âfetchâ (podrobnosti o operacÃch na Blob najdete v kapitole Blob):
let odpovÄÄ = await fetch('/article/fetch/logo-fetch.svg');
let blob = await odpovÄÄ.blob(); // stáhneme jako objekt Blob
// vytvoÅÃme z nÄj <img>
let obrázek = document.createElement('img');
obrázek.style = 'position:fixed;top:10px;left:10px;width:100px';
document.body.append(obrázek);
// zobrazÃme jej
obrázek.src = URL.createObjectURL(blob);
setTimeout(() => { // po tÅech sekundách zmizÃ
obrázek.remove();
URL.revokeObjectURL(obrázek.src);
}, 3000);
Můžeme si zvolit pouze jednu metodu naÄtenà tÄla.
Jestliže jsme odpovÄÄ již zÃskali volánÃm odpovÄÄ.text(), pak následné odpovÄÄ.json() nebude fungovat, neboÅ¥ obsah tÄla již byl zpracován.
let text = await odpovÄÄ.text(); // tÄlo odpovÄdi je spotÅebováno
let parsovaný = await odpovÄÄ.json(); // selže (tÄlo je již spotÅebováno)
HlaviÄky odpovÄdi
HlaviÄky odpovÄdi jsou k dispozici v objektu odpovÄÄ.headers, který je podobný mapÄ.
Nenà to pÅesnÄ Map, ale obsahuje podobné metody k zÃskánà jednotlivých hlaviÄek podle názvu nebo k iteraci nad nimi:
let odpovÄÄ = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
// zÃskáme jednu hlaviÄku
alert(odpovÄÄ.headers.get('Content-Type')); // application/json; charset=utf-8
// iterujeme nad vÅ¡emi hlaviÄkami
for (let [klÃÄ, hodnota] of odpovÄÄ.headers) {
alert(`${klÃÄ} = ${hodnota}`);
}
HlaviÄky požadavku
K nastavenà hlaviÄek požadavku v metodÄ fetch můžeme použÃt volbu headers, která obsahuje objekt s odesÃlanými hlaviÄkami, napÅÃklad:
let odpovÄÄ = fetch(chránÄnéURL, {
headers: {
Authentication: 'secret'
}
});
â¦Existuje vÅ¡ak seznam zakázaných HTTP hlaviÄek, které nastavit nemůžeme:
Accept-Charset,Accept-EncodingAccess-Control-Request-HeadersAccess-Control-Request-MethodConnectionContent-LengthCookie,Cookie2DateDNTExpectHostKeep-AliveOriginRefererTETrailerTransfer-EncodingUpgradeViaProxy-*Sec-*
Tyto hlaviÄky zajišťujà správný a bezpeÄný HTTP, takže jsou nastavovány výluÄnÄ prohlÞeÄem.
Požadavky POST
K vytvoÅenà požadavku POST nebo s nÄjakou jinou metodou musÃme nastavit ve volbách metody fetch:
methodâ HTTP metoda, napÅ.POST,bodyâ tÄlo požadavku, jedno z následujÃcÃch:- ÅetÄzec (napÅ. zakódovaný v JSONu),
- objekt
FormDatak odeslánà dat jakomultipart/form-data, Blob/BufferSourcek odeslánà binárnÃch dat,- URLSearchParams, k odeslánà dat v kódovánÃ
x-www-form-urlencoded, použÃváno zÅÃdka.
Ve vÄtÅ¡inÄ pÅÃpadů se použÃvá formát JSON.
NapÅÃklad tento kód odeÅ¡le objekt uživatel jako JSON:
let uživatel = {
jméno: 'Jan',
pÅÃjmenÃ: 'Novák'
};
let odpovÄÄ = await fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(uživatel)
});
let výsledek = await odpovÄÄ.json();
alert(výsledek.message);
ProsÃme vÅ¡imnÄte si, že jestliže je body požadavku ÅetÄzec, pak se hlaviÄka Content-Type standardnÄ nastavà na text/plain;charset=UTF-8.
Pokud vÅ¡ak chceme poslat JSON, použijeme volbu headers, abychom mÃsto toho poslali application/json, správný Content-Type pro data zakódovaná v JSONu.
Poslánà obrázku
Metodou fetch můžeme také poslat binárnà data pomocà objektů Blob nebo BufferSource.
V následujÃcÃm pÅÃkladu máme <canvas>, do nÄhož můžeme kreslit pohybem myÅ¡i nad nÃm. KliknutÃm na tlaÄÃtko âOdeslatâ poÅ¡leme obrázek na server:
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Odeslat" onclick="odeslat()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function odeslat() {
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
let odpovÄÄ = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});
// server odpovà potvrzenÃm a velikostà obrázku
let výsledek = await odpovÄÄ.json();
alert(výsledek.message);
}
</script>
</body>
ProsÃme vÅ¡imnÄte si, že zde nenastavujeme Content-Type ruÄnÄ, protože objekt Blob obsahuje vestavÄný typ (zde image/png, který je generován metodou toBlob). PÅi odesÃlánà objektu Blob bude hodnota Content-Type nastavena na tento typ.
Funkci odeslat() můžeme pÅepsat bez použità async/await následovnÄ:
function odeslat() {
canvasElem.toBlob(function(blob) {
fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
})
.then(odpovÄÄ => odpovÄÄ.json())
.then(výsledek => alert(JSON.stringify(výsledek, null, 2)))
}, 'image/png');
}
ShrnutÃ
Obvyklý požadavek na staženà se skládá ze dvou volánà await:
let odpovÄÄ = await fetch(url, volby); // vyhodnotà se s hlaviÄkami odpovÄdi
let výsledek = await odpovÄÄ.json(); // naÄte tÄlo jako JSON
Nebo bez await:
fetch(url, volby)
.then(odpovÄÄ => odpovÄÄ.json())
.then(výsledek => /* zpracovánà výsledku */)
Vlastnosti odpovÄdi:
odpovÄÄ.statusâ HTTP kód odpovÄdi,odpovÄÄ.okâtrue, pokud status je 200-299,odpovÄÄ.headersâ objekt podobný Map s HTTP hlaviÄkami.
Metody pro zÃskánà tÄla odpovÄdi:
response.text()â vrátà odpovÄÄ jako text,response.json()â rozparsuje odpovÄÄ ve formátu JSON do objektu,response.formData()â vrátà odpovÄÄ jako objektFormData(kódovánÃmultipart/form-data, viz pÅÃÅ¡tà kapitolu),response.blob()â vrátà odpovÄÄ jako blob (binárnà data s typem),response.arrayBuffer()â vrátà odpovÄÄ jako ArrayBuffer (nÃzkoúrovÅová reprezentace binárnÃch dat).
Dosud uvedené volby stahovánÃ:
methodâ HTTP metoda,headersâ objekt s hlaviÄkami požadavku (ne vÅ¡echny hlaviÄky jsou povoleny),bodyâ data k odeslánà (tÄlo požadavku) jako objektstring,FormData,BufferSource,BlobneboUrlSearchParams.
V pÅÃÅ¡tà kapitole uvidÃme dalšà volby a pÅÃpady použità metody fetch.
KomentáÅe
<code>, pro nÄkolik Åádků je obalte znaÄkou<pre>, pro vÃce než 10 Åádků vložte odkaz na pÃskoviÅ¡tÄ (plnkr, jsbin, codepenâ¦)