Vynést

JavaScript může odesílat síťové požadavky na server a načítat nové informace, kdykoli je to potřeba.

Síťový požadavek můžeme například použít k:

  • odešlete objednávku,
  • Načíst informace o uživateli,
  • Přijímat nejnovější aktualizace ze serveru,
  • …atd.

…A to vše bez opětovného načítání stránky!

Existuje zastřešující termín „AJAX“ (zkráceně A synchronní J avaScript A a X ML) pro síťové požadavky z JavaScriptu. Nemusíme však používat XML:termín pochází ze starých časů, proto tam toto slovo je. Možná jste tento termín již slyšeli.

Existuje několik způsobů, jak odeslat síťový požadavek a získat informace ze serveru.

fetch() metoda je moderní a všestranná, tak s ní začneme. Není podporován starými prohlížeči (lze být polyfilled), ale mezi moderními je velmi dobře podporován.

Základní syntaxe je:

let promise = fetch(url, [options])
  • url – URL pro přístup.
  • options – volitelné parametry:metoda, hlavičky atd.

Bez options , toto je jednoduchý požadavek GET, který stahuje obsah url .

Prohlížeč okamžitě spustí požadavek a vrátí příslib, který má volací kód použít k získání výsledku.

Získání odpovědi je obvykle dvoufázový proces.

Za prvé, promise , vráceno fetch , řeší pomocí objektu vestavěné třídy Response, jakmile server odpoví hlavičkami.

V této fázi můžeme zkontrolovat stav HTTP, zda je úspěšný nebo ne, zkontrolovat záhlaví, ale ještě nemáme tělo.

Příslib odmítne, pokud fetch nemohl provést požadavek HTTP, např. problémy se sítí nebo taková stránka neexistuje. Abnormální stavy HTTP, jako je 404 nebo 500, nezpůsobují chybu.

Ve vlastnostech odpovědi můžeme vidět stav HTTP:

  • status – stavový kód HTTP, např. 200.
  • ok – boolean, true pokud je stavový kód HTTP 200-299.

Například:

let response = await fetch(url);

if (response.ok) { // if HTTP-status is 200-299
  // get the response body (the method explained below)
  let json = await response.json();
} else {
  alert("HTTP-Error: " + response.status);
}

Zadruhé, abychom získali tělo odpovědi, musíme použít další volání metody.

Response poskytuje několik metod založených na slibech pro přístup k tělu v různých formátech:

  • response.text() – přečíst odpověď a vrátit se jako text,
  • response.json() – analyzovat odpověď jako JSON,
  • response.formData() – vrátí odpověď jako FormData objekt (vysvětleno v další kapitole),
  • response.blob() – vrátí odpověď jako Blob (binární data s typem),
  • response.arrayBuffer() – vrátit odpověď jako ArrayBuffer (nízkoúrovňová reprezentace binárních dat),
  • navíc response.body je objekt ReadableStream, umožňuje vám číst tělo kousek po kousku, příklad uvidíme později.

Pojďme například získat objekt JSON s nejnovějšími commity z GitHubu:

let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
let response = await fetch(url);

let commits = await response.json(); // read response body and parse as JSON

alert(commits[0].author.login);

Nebo totéž bez await , pomocí syntaxe čistých slibů:

fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits')
  .then(response => response.json())
  .then(commits => alert(commits[0].author.login));

Chcete-li získat text odpovědi, await response.text() místo .json() :

let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');

let text = await response.text(); // read response body as text

alert(text.slice(0, 80) + '...');

Jako ukázku pro čtení v binárním formátu si načtěte a ukažme obrázek loga specifikace „fetch“ (podrobnosti o operacích na Blob najdete v kapitole Blob ):

let response = await fetch('/article/fetch/logo-fetch.svg');

let blob = await response.blob(); // download as Blob object

// create <img> for it
let img = document.createElement('img');
img.style = 'position:fixed;top:10px;left:10px;width:100px';
document.body.append(img);

// show it
img.src = URL.createObjectURL(blob);

setTimeout(() => { // hide after three seconds
  img.remove();
  URL.revokeObjectURL(img.src);
}, 3000);
Důležité:

Můžeme si vybrat pouze jednu metodu čtení těla.

Pokud již máme odpověď s response.text() a poté response.json() nebude fungovat, protože obsah těla již byl zpracován.

let text = await response.text(); // response body consumed
let parsed = await response.json(); // fails (already consumed)

Záhlaví odpovědí

Záhlaví odpovědí jsou k dispozici v objektu záhlaví podobného mapě v response.headers .

Není to přesně mapa, ale má podobné metody, jak získat jednotlivá záhlaví podle názvu nebo přes ně iterovat:

let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');

// get one header
alert(response.headers.get('Content-Type')); // application/json; charset=utf-8

// iterate over all headers
for (let [key, value] of response.headers) {
  alert(`${key} = ${value}`);
}

Záhlaví požadavků

Chcete-li nastavit záhlaví požadavku v fetch , můžeme použít headers volba. Má objekt s odchozími záhlavími, jako je tento:

let response = fetch(protectedUrl, {
  headers: {
    Authentication: 'secret'
  }
});

…Ale existuje seznam zakázaných HTTP hlaviček, které nemůžeme nastavit:

  • Accept-Charset , Accept-Encoding
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Connection
  • Content-Length
  • Cookie , Cookie2
  • Date
  • DNT
  • Expect
  • Host
  • Keep-Alive
  • Origin
  • Referer
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade
  • Via
  • Proxy-*
  • Sec-*

Tyto hlavičky zajišťují správný a bezpečný HTTP, takže je ovládá výhradně prohlížeč.

Požadavky POST

Chcete-li vytvořit POST požadavek nebo požadavek s jinou metodou, musíme použít fetch možnosti:

  • method – metoda HTTP, např. POST ,
  • body – tělo požadavku, jeden z:
    • řetězec (např. s kódováním JSON),
    • FormData objekt, odešlete data jako multipart/form-data ,
    • Blob /BufferSource k odesílání binárních dat,
    • URLSearchParams, chcete-li odeslat data v x-www-form-urlencoded kódování, zřídka používané.

Nejčastěji se používá formát JSON.

Tento kód například odešle user objekt jako JSON:

let user = {
  name: 'John',
  surname: 'Smith'
};

let response = await fetch('/article/fetch/post/user', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  },
  body: JSON.stringify(user)
});

let result = await response.json();
alert(result.message);

Upozorňujeme, že pokud je požadavek body je řetězec, pak Content-Type záhlaví je nastaveno na text/plain;charset=UTF-8 ve výchozím nastavení.

Ale když budeme odesílat JSON, používáme headers možnost odeslat application/json místo toho správné Content-Type pro data kódovaná JSON.

Odeslání obrázku

Můžeme také odeslat binární data s fetch pomocí Blob nebo BufferSource objektů.

V tomto příkladu je <canvas> kde můžeme kreslit pohybem myši nad ním. Kliknutím na tlačítko „odeslat“ odešlete obrázek na server:

<body style="margin:0">
  <canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>

  <input type="button" value="Submit" onclick="submit()">

  <script>
    canvasElem.onmousemove = function(e) {
      let ctx = canvasElem.getContext('2d');
      ctx.lineTo(e.clientX, e.clientY);
      ctx.stroke();
    };

    async function submit() {
      let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
      let response = await fetch('/article/fetch/post/image', {
        method: 'POST',
        body: blob
      });

      // the server responds with confirmation and the image size
      let result = await response.json();
      alert(result.message);
    }

  </script>
</body>

Upozorňujeme, že zde nenastavujeme Content-Type záhlaví ručně, protože Blob objekt má vestavěný typ (zde image/png , jak je vygenerováno toBlob ). Pro Blob objekty, které zadávají, se stanou hodnotou Content-Type .

submit() funkci lze přepsat bez async/await takhle:

function submit() {
  canvasElem.toBlob(function(blob) {
    fetch('/article/fetch/post/image', {
      method: 'POST',
      body: blob
    })
      .then(response => response.json())
      .then(result => alert(JSON.stringify(result, null, 2)))
  }, 'image/png');
}

Shrnutí

Typický požadavek na načtení se skládá ze dvou await volání:

let response = await fetch(url, options); // resolves with response headers
let result = await response.json(); // read body as json

Nebo bez await :

fetch(url, options)
  .then(response => response.json())
  .then(result => /* process result */)

Vlastnosti odpovědi:

  • response.status – HTTP kód odpovědi,
  • response.oktrue pokud je stav 200–299.
  • response.headers – Objekt podobný mapě s HTTP hlavičkami.

Metody získání těla odpovědi:

  • response.text() – vrátit odpověď jako text,
  • response.json() – analyzovat odpověď jako objekt JSON,
  • response.formData() – vrátí odpověď jako FormData objekt (multipart/form-data kódování, viz další kapitola),
  • response.blob() – vrátí odpověď jako Blob (binární data s typem),
  • response.arrayBuffer() – vrátit odpověď jako ArrayBuffer (nízkoúrovňová binární data),

Možnosti načítání zatím:

  • method – metoda HTTP,
  • headers – objekt s hlavičkami požadavku (není povolena žádná hlavička),
  • body – data k odeslání (tělo požadavku) jako string , FormData , BufferSource , Blob nebo UrlSearchParams objekt.

V dalších kapitolách uvidíme další možnosti a případy použití fetch .