web-dev-qa-db-fra.com

Télécharger les données de réponse en tant que flux avec Axios dans React App

Problème

Je dois télécharger les résultats de la requête à partir d'un point de terminaison en diffusant les résultats dans un fichier CSV. Il s'agit d'un effort pour prendre en charge d'énormes ResultSets envoyés via le navigateur en même temps.

Existe-t-il un moyen d'accomplir cela en utilisant Axios dans le contexte d'une React App?

J'ai vu fetch () et je sais qu'il a les caractéristiques suivantes:

  • renvoie ReadableStream
  • N'est PAS pris en charge par IE11
  • Ne permet PAS d'intercepter les demandes
  • L'état d'une réponse se rapporte à la requête elle-même, pas à l'état HTTP
    • Cela signifie que la seule façon de recevoir une erreur serait d'avoir un problème avec le flux se terminant prématurément
    • Cela ne fonctionnera certainement pas pour moi car j'ai une gestion des erreurs personnalisée liée aux autorisations des utilisateurs

Outre le type de réponse ReadableStream, les autres caractéristiques répertoriées ne sont pas autorisées. J'aurai besoin de prendre en charge IE11 et de permettre l'interception des demandes/la lecture de l'état HTTP pour déterminer comment gérer le trafic.

Exemple avec fetch:

      // The promise returned by `fetch` rejects if the fetch was unable to make HTTP-request
      //  e.g. network problems, or there’s no such site.
      // Abnormal HTTP-statuses, such as 404 or 500 do not cause an error.
      const results = await fetch(`${URL}/data`, {
        method: 'post', // HTTP POST to send query to server
        headers: {
          Accept: 'application/json, text/plain, */*', // indicates which files we are able to understand
          'Content-Type': 'application/json', // indicates what the server actually sent
        },
        body: JSON.stringify(query), // server is expecting JSON
        credentials: 'include', // sends the JSESSIONID cookie with the address
      }).then(res => res.json()) // turn the ReadableStream response back into JSON
        .then((res) => {
          if (res.ok) {
            // boolean, true if the HTTP status code is 200-299.
            console.log('response.ok!');
          } else if (res.status === 401) {
            throw Error(`You are not authenticated. Please login.`);
          } else if (res.status === 403) {
            throw Error(`You are not authorized to access this data.`);
          } else {
            throw Error(`Request rejected with status ${res.status}`);
          }
        })
        .catch((error) => {
          // catches error case and if fetch itself rejects
          error.response = {
            status: 0,
            statusText:
              'Cannot connect. Please make sure you are connected to internet.',
          };
          throw error;
        });

      console.log(results);

Exemple avec axios (pas de streaming)

Instance Axios

import ...
const Api = axios.create({
  baseURL: `${URL}`,
  withCredentials: true,
});

// attach interceptors to requests and responses
// these are defined elsewhere and imported
Api.interceptors.request.use((request) => requestHandler(request));
Api.interceptors.response.use((response) => successHandler(response), (error) => errorHandler(error));

export default Api;

Demande Axios

const query = {"selections":{"TABLE_A":["COLUMN1"]},"filters":[{"predicates":[]}],"joins":[],"sorts":[],"limit":100,"offset":0}
const response = await Api.post('/data', query);
// further transformations to response to get formatted csv results required

Questions sur Axios

  • Est-il possible d'avoir un ReadableStream dans Axios comme fetch?
  • Le streaming dans Axios n'est-il possible que si l'on suppose qu'il sera pris en charge par Node dans un paramètre côté serveur uniquement?
    • Des sites comme this semblent indiquer que l'utilisation de responseType: 'stream' n'est pas quelque chose qui peut être fait dans le navigateur, uniquement avec Node.js en utilisant fs
  • Est-il possible d'utiliser fetch ou autre chose en conjonction avec Axios?
4
Joe H

La diffusion d'une réponse depuis le navigateur n'est pas actuellement prise en charge:

https://github.com/axios/axios/issues/479

Puisque nous avons affaire à XMLHttpRequests dans le navigateur, Axios est limité à la spécification définie par whatwg. :

Plus précisément, ce sont les seuls types pris en charge:

enum XMLHttpRequestResponseType {
  "",
  "arraybuffer",
  "blob",
  "document",
  "json",
  "text"
};

stream est accepté lors de la définition d'un responseType dans axios, mais c'est trompeur. L'adaptateur sera xhr.js implicitement puisque nous utilisons le navigateur qui repose sur XMLHttpRequests. Les requêtes HttpRequests sont effectuées côté serveur et permettront à axios d'utiliser le http.js adaptateur. ALORS vous pouvez utiliser stream comme ResponseType avec Node.js.

L'utilisation de l'API fetch semble être la seule solution avec un ReadableStream comme type de corps de réponse.

3
Joe H