Introduzione alla funzione fetch()

L'API fetch() sta arrivando nell'oggetto finestra e sta cercando di sostituire gli XHR

Matt Gaunt

XMLHttpRequest finora

fetch() ti consente di effettuare richieste di rete simili a XMLHttpRequest (XHR). La differenza principale è che l'API Fetch utilizza Promises, che consente un'API più semplice e più pulita, evitando l'inferno dei callback e dover ricordare la complessa API di XMLHttpRequest.

Supporto dei browser

  • 42
  • 14
  • 39
  • 10.1

Fonte

L'API Fetch è disponibile nell'ambito globale Service Worker a partire da Chrome 40, ma verrà abilitata nell'ambito delle finestre in Chrome 42. Esiste anche un polyfill di GitHub piuttosto reattivo che puoi usare oggi.

Se non hai mai utilizzato Promise, consulta Introduzione alle promesse di JavaScript.

Richiesta di recupero di base

Cominciamo con il confronto di un semplice esempio implementato con XMLHttpRequest e poi con fetch. Vogliamo solo richiedere un URL, ricevere una risposta e analizzarlo come JSON.

XMLHttpRequest

Un XMLHttpRequest richiede che siano impostati due listener per gestire i casi di successo ed errore e una chiamata a open() e send(). Esempio da documenti MDN.

function reqListener() {
    var data = JSON.parse(this.responseText);
    console.log(data);
}

function reqError(err) {
    console.log('Fetch Error :-S', err);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

Recupero

La nostra richiesta di recupero è simile alla seguente:

fetch('./api/some.json')
    .then(
    function(response) {
        if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
            response.status);
        return;
        }

        // Examine the text in the response
        response.json().then(function(data) {
        console.log(data);
        });
    }
    )
    .catch(function(err) {
    console.log('Fetch Error :-S', err);
    });

Per prima cosa, verifica che lo stato della risposta sia 200 prima di analizzare la risposta come JSON.

La risposta di una richiesta fetch() è un oggetto Stream, il che significa che quando chiamiamo il metodo json(), viene restituita una Promise poiché la lettura del flusso avviene in modo asincrono.

Metadati delle risposte

Nell'esempio precedente abbiamo esaminato lo stato dell'oggetto Response e come analizzare la risposta come JSON. Gli altri metadati a cui possiamo voler accedere, come le intestazioni, sono illustrati di seguito.

fetch('users.json').then(function(response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
});

Tipi di risposta

Quando effettuiamo una richiesta di recupero, la risposta riceverà un valore response.type di "basic", "cors" o "opaque". Questi valori types indicano la provenienza della risorsa e possono essere utilizzati per indicare come trattare l'oggetto risposta.

Quando viene effettuata una richiesta per una risorsa sulla stessa origine, la risposta avrà un tipo basic e non ci sono limitazioni su ciò che puoi visualizzare dalla risposta.

Se viene effettuata una richiesta per una risorsa su un'altra origine che restituisce le intestazioni COR, il tipo è cors. Le risposte cors e basic sono quasi identiche, tranne per il fatto che una risposta cors limita le intestazioni che puoi visualizzare a Cache-Control, Content-Language, Content-Type, Expires, Last-Modified e Pragma.

Una risposta opaque è relativa a una richiesta effettuata per una risorsa in un'origine diversa che non restituisce intestazioni CORS. Con una risposta opaca non saremo in grado di leggere i dati restituiti o visualizzare lo stato della richiesta, il che significa che non possiamo verificare se la richiesta è andata a buon fine o meno.

Puoi definire una modalità per una richiesta di recupero in modo che solo determinate richieste vengano risolte. Le modalità che puoi impostare sono le seguenti:

  • same-origin ha esito positivo solo per le richieste di asset sulla stessa origine; tutte le altre richieste verranno rifiutate.
  • cors consentirà le richieste di asset sulla stessa origine e in altre origini che restituiscono le intestazioni COR appropriate.
  • cors-with-forced-preflight eseguirà sempre un controllo preflight prima di effettuare la richiesta effettiva.
  • no-cors ha lo scopo di effettuare richieste ad altre origini che non hanno intestazioni CORS e generano una risposta opaque, ma, come indicato, al momento non è possibile nell'ambito globale della finestra.

Per definire la modalità, aggiungi un oggetto opzioni come secondo parametro nella richiesta fetch e definisci la modalità in tale oggetto:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
    .then(function(response) {
    return response.text();
    })
    .then(function(text) {
    console.log('Request successful', text);
    })
    .catch(function(error) {
    log('Request failed', error)
    });

Concatenamento delle promesse

Una delle grandi caratteristiche delle promesse è la possibilità di collegarle tra loro. Per il recupero, puoi condividere la logica tra le richieste di recupero.

Se utilizzi un'API JSON, dovrai controllare lo stato e analizzare il codice JSON per ogni risposta. Per semplificare il codice, puoi definire lo stato e l'analisi JSON in funzioni separate che restituiscono promesse, in modo da non doverti più preoccupare della gestione dei dati finali e del caso di errore.

function status(response) {
    if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
    } else {
    return Promise.reject(new Error(response.statusText))
    }
}

function json(response) {
    return response.json()
}

fetch('users.json')
    .then(status)
    .then(json)
    .then(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

Definiamo la funzione status che controlla response.status e restituisce il risultato di Promise.resolve() o Promise.reject(), che restituisce una Promessa risolta o rifiutata. Questo è il primo metodo chiamato nella nostra catena fetch(). Se si risolve, chiamiamo il nostro metodo json() che restituisce di nuovo una Promise dalla chiamata response.json(). Dopo avremo un oggetto del JSON analizzato. Se l'analisi non va a buon fine, la promessa viene rifiutata e viene eseguita l'istruzione catch.

Il vantaggio è che puoi condividere la logica tra tutte le tue richieste di recupero, semplificando così la gestione, la lettura e il test del codice.

Richiesta POST

Non è raro che le app web vogliano chiamare un'API con un metodo POST e fornire alcuni parametri nel corpo della richiesta.

Per farlo, possiamo impostare i parametri method e body nelle opzioni fetch().

fetch(url, {
    method: 'post',
    headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
    })
    .then(json)
    .then(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

Invio di credenziali con una richiesta di recupero

Se vuoi effettuare una richiesta di recupero con credenziali come i cookie, devi impostare il valore credentials della richiesta su "include".

fetch(url, {
    credentials: 'include'
})

Domande frequenti

Come faccio ad annullare una richiesta fetch()?

Al momento non è possibile annullare un recupero, ma è in corso una spiegazione su GitHub. H/T @jaffathecake per questo link.

È presente un polyfill?

GitHub ha un polyfill per il recupero. H/T @Nexii per averlo fatto presente.

Perché "no-cors" è supportato nei service worker ma non nella finestra?

Il problema è dovuto a un problema di sicurezza. Scopri di più qui.