Implementa la gestione degli errori durante l'utilizzo dell'API Fetch

Umar Hansa
Umar Hansa

Questo articolo illustra alcuni approcci alla gestione degli errori quando si utilizza l'API Fetch. L'API Fetch ti consente di inviare una richiesta a una risorsa di rete remota. Quando effettui una chiamata di rete remota, la tua pagina web diventa soggetta a una serie di potenziali errori di rete.

Le sezioni seguenti descrivono potenziali errori e spiegano come scrivere codice che offra un livello ragionevole di funzionalità e sia resiliente a errori e condizioni di rete impreviste. Il codice resiliente mantiene soddisfatti gli utenti e garantisce un livello di servizio standard per il tuo sito web.

Questa sezione descrive uno scenario in cui l'utente crea un nuovo video denominato "My Travels.mp4" e poi tenta di caricare il video su un sito web di condivisione video.

Quando utilizzi Fetch, è facile considerare il percorso ottimale in cui l'utente carica correttamente il video. Tuttavia, esistono altri percorsi non così semplici, che gli sviluppatori web devono pianificare. Questi percorsi (insoddisfacenti) possono verificarsi a causa di un errore dell'utente, di condizioni ambientali impreviste o di un bug sul sito web di condivisione video.

Esempi di errori utente

  • L'utente carica un file immagine (ad esempio JPEG) anziché un file video.
  • L'utente inizia a caricare il file video sbagliato. A metà caricamento, l'utente specifica il file video corretto da caricare.
  • L'utente fa clic accidentalmente su "Annulla caricamento" durante il caricamento del video.

Esempi di modifiche ambientali

  • La connessione a internet diventa offline durante il caricamento del video.
  • Il browser si riavvia durante il caricamento del video.
  • I server del sito web di condivisione video si riavviano durante il caricamento del video.

Esempi di errori relativi al sito web di condivisione di video

  • Il sito di condivisione video non può gestire un nome file con uno spazio. Al posto di "My Travels.mp4", è previsto un nome come "My_Travels.mp4" o "MyTravels.mp4".
  • Il sito web di condivisione video non può caricare video che superano le dimensioni massime consentite dei file.
  • Il sito web di condivisione video non supporta il codec video del video caricato.

Questi esempi possono e si verificano nel mondo reale. Forse hai già visto questi esempi in passato. Scegliamo un esempio per ciascuna delle categorie precedenti e discutiamo i seguenti punti:

  • Qual è il comportamento predefinito se il servizio di condivisione video non è in grado di gestire l'esempio in questione?
  • Cosa si aspetta l'utente nell'esempio?
  • Come possiamo migliorare la procedura?
Azione L'utente inizia a caricare il file video sbagliato. A metà caricamento, l'utente specifica il file video corretto da caricare.
Cosa succede per impostazione predefinita Il file originale continua a essere caricato in background contemporaneamente al nuovo file.
Ciò che l'utente si aspetta L'utente si aspetta che il caricamento originale venga interrotto in modo da non sprecare larghezza di banda di internet.
Cosa può essere migliorato JavaScript annulla la richiesta di recupero del file originale prima dell'inizio del caricamento del nuovo file.
Azione L'utente perde la connessione a internet a metà caricamento del video.
Cosa succede per impostazione predefinita La barra di avanzamento del caricamento sembra essere bloccata al 50%. Alla fine, l'API Fetch si arresta in caso di timeout e i dati caricati vengono eliminati. Quando la connettività a internet viene ripristinata, l'utente deve ricaricare il file.
Ciò che l'utente si aspetta L'utente si aspetta di ricevere una notifica quando non è possibile caricare il file e che il caricamento riprenda automaticamente al 50% quando è di nuovo online.
Che cosa può essere migliorato La pagina di caricamento informa l'utente dei problemi di connettività a internet e lo rassicura sul fatto che il caricamento riprenderà quando la connettività a internet sarà ripristinata.
Azione Il sito di condivisione video non può gestire un nome file con uno spazio. Anziché "I miei viaggi.mp4", sono previsti nomi come "I_miei_viaggi.mp4" o "I miei viaggi.mp4".
Che cosa succede per impostazione predefinita L'utente deve attendere il completamento del caricamento. Una volta caricato il file, la barra di avanzamento indica "100%" e viene visualizzato il messaggio "Riprova".
Ciò che l'utente si aspetta L'utente si aspetta di essere informato delle limitazioni relative ai nomi file prima dell'inizio del caricamento o almeno entro il primo secondo del caricamento.
Che cosa può essere migliorato Idealmente, il servizio di condivisione video supporta i nomi di file con spazi. In alternativa, puoi informare l'utente delle limitazioni relative ai nomi file prima dell'inizio del caricamento. In alternativa, il servizio di condivisione video dovrebbe rifiutare il caricamento con un messaggio di errore dettagliato.

Gestire gli errori con l'API Fetch

Tieni presente che i seguenti esempi di codice utilizzano await di primo livello (supporto del browser) perché questa funzionalità può semplificare il codice.

Quando l'API Fetch genera errori

Questo esempio utilizza un'istruzione blocco try/catch per rilevare eventuali errori generati all'interno del blocco try. Ad esempio, se l'API Fetch non riesce a recuperare la risorsa specificata, viene generato un errore. All'interno di un blocco catch come questo, assicurati di offrire un'esperienza utente significativa. Se all'utente viene mostrato uno spinner, un'interfaccia utente comune che rappresenta una sorta di avanzamento, puoi eseguire le seguenti azioni all'interno di un blocco catch:

  1. Rimuovi la rotellina dalla pagina.
  2. Fornisci messaggi utili che spieghino cosa non ha funzionato e quali opzioni sono disponibili per l'utente.
  3. In base alle opzioni disponibili, presenta all'utente un pulsante "Riprova".
  4. Dietro le quinte, invia i dettagli dell'errore al tuo servizio di monitoraggio degli errori o al back-end. Questa azione registra l'errore in modo che possa essere diagnosticato in un secondo momento.
try {
  const response = await fetch('https://website');
} catch (error) {
  // TypeError: Failed to fetch
  console.log('There was an error', error);
}

In un secondo momento, mentre diagnostichi l'errore registrato, puoi scrivere un caso di test per rilevare questo tipo di errore prima che gli utenti si accorgano che c'è un problema. A seconda dell'errore, il test può essere di unità, di integrazione o di accettazione.

Quando il codice di stato della rete rappresenta un errore

Questo esempio di codice invia una richiesta a un servizio di test HTTP che risponde sempre con il codice di stato HTTP 429 Too Many Requests. È interessante notare che la risposta non raggiunge il blocco catch. Uno stato 404, tra altri codici di stato, non restituisce un errore di rete, ma si risolve normalmente.

Per verificare che il codice di stato HTTP sia riuscito, puoi utilizzare una delle seguenti opzioni:

  • Utilizza la proprietà Response.ok per determinare se il codice di stato rientra nell'intervallo da 200 a 299.
  • Utilizza la proprietà Response.status per determinare se la risposta è andata a buon fine.
  • Utilizza altri metadati, ad esempio Response.headers, per valutare se la risposta è andata a buon fine.
let response;

try {
  response = await fetch('https://httpbin.org/status/429');
} catch (error) {
  console.log('There was an error', error);
}

// Uses the 'optional chaining' operator
if (response?.ok) {
  console.log('Use the response here!');
} else {
  console.log(`HTTP Response Code: ${response?.status}`)
}

La best practice è collaborare con le persone della tua organizzazione e del tuo team per comprendere i potenziali codici di stato di risposta HTTP. A volte, gli sviluppatori di backend, gli addetti alle operazioni di sviluppo e gli ingegneri di servizio possono fornire informazioni uniche su possibili casi limite che potresti non prevedere.

Quando si verifica un errore durante l'analisi della risposta di rete

Questo esempio di codice mostra un altro tipo di errore che può verificarsi durante l'analisi del corpo di una risposta. L'interfaccia Response offre metodi pratici per analizzare diversi tipi di dati, come testo o JSON. Nel codice seguente, viene fatta una richiesta di rete a un servizio di test HTTP che restituisce una stringa HTML come corpo della risposta. Tuttavia, viene tentato di analizzare il corpo della risposta come JSON, generando un errore.

let json;

try {
  const response = await fetch('https://httpbin.org/html');
  json = await response.json();
} catch (error) {
  if (error instanceof SyntaxError) {
    // Unexpected token < in JSON
    console.log('There was a SyntaxError', error);
  } else {
    console.log('There was an error', error);
  }
}

if (json) {
  console.log('Use the JSON here!', json);
}

Devi preparare il codice in modo che accetti una serie di formati di risposta e verificare che una risposta imprevista non interrompa la pagina web per l'utente.

Considera il seguente scenario: hai una risorsa remota che restituisce una risposta JSON valida ed è analizzata correttamente con il metodo Response.json(). Può accadere che il servizio non sia disponibile. Al termine, viene restituito un valore 500 Internal Server Error. Se durante l'analisi del JSON non vengono utilizzate tecniche di gestione degli errori appropriate, la pagina potrebbe non essere visualizzata dall'utente perché viene generato un errore non gestito.

Quando la richiesta di rete deve essere annullata prima del completamento

In questo esempio di codice viene utilizzato un elemento AbortController per annullare una richiesta in corso di pubblicazione. Una richiesta in corso è una richiesta di rete che è stata avviata, ma non è stata completata.

Gli scenari in cui potresti dover annullare una richiesta in corso possono variare, ma in ultima analisi dipendono dal caso d'uso e dall'ambiente. Il seguente codice mostra come passare un AbortSignal all'API Fetch. AbortSignal è associato a un AbortController, che include un metodo abort(), che indica al browser che la richiesta di rete deve essere annullata.

const controller = new AbortController();
const signal = controller.signal;

// Cancel the fetch request in 500ms
setTimeout(() => controller.abort(), 500);

try {
  const url = 'https://httpbin.org/delay/1';
  const response = await fetch(url, { signal });
  console.log(response);
} catch (error) {
  // DOMException: The user aborted a request.
  console.log('Error: ', error)
}

Conclusione

Un aspetto importante della gestione degli errori è definire le varie parti che possono andare storte. Per ogni scenario, assicurati di avere implementato un piano di riserva appropriato per l'utente. In merito a una richiesta di recupero, poniti domande come:

  • Che cosa succede se il server di destinazione non è disponibile?
  • Che cosa succede se Fetch riceve una risposta imprevista?
  • Cosa succede se la connessione a internet dell'utente non va a buon fine?

A seconda della complessità della pagina web, puoi anche abbozzare un diagramma di flusso che descriva la funzionalità e l'interfaccia utente per diversi scenari.