web-dev-qa-db-ja.com

ReactアプリでAxiosを使用して応答データをストリームとしてダウンロード

問題

結果をCSVファイルにストリーミングして、クエリ結果をエンドポイントからダウンロードする必要があります。これは、ブラウザーを介して一度に送信される膨大なResultSetをサポートするための作業です。

ReactアプリのコンテキストでAxiosを使用してこれを達成する方法はありますか?

私は fetch() を見て、次の特徴があることを知っています:

  • readableStreamを返します
  • IE11ではサポートされていません
  • リクエストを傍受することはできません
  • 応答のstatusは、HTTPステータスではなく、リクエスト自体に関連します
    • つまり、エラーを受け取る唯一の方法は、ストリームが途中で終了することで何かがうまくいかないことです。
    • ユーザー権限に関連するカスタムのエラー処理があるので、これは私には間違いなく機能しません

ReadableStream応答タイプ以外に、リストされている残りの特性は許可されていません。 IE11をサポートし、リクエストのインターセプトやHTTPステータスの読み取りを可能にして、トラフィックの処理方法を決定する必要があります。

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);

axiosの例(ストリーミングではない)

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;

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

Axiosに関する質問

  • AxiosでReadableStreamfetchと同じにすることはできますか?
  • Axiosでのストリーミングは、サーバー側のみの設定でNodeによってサポートされることを想定している場合にのみ可能ですか?
    • this のようなサイトは、responseType: 'stream'はブラウザで実行できるものではなく、Node.jsでfsを使用した場合のみ可能です
  • Axiosと組み合わせてfetchまたは他の何かを使用することは可能ですか?
4
Joe H

ブラウザからの応答のストリーミングは現在サポートされていません:

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

ブラウザーではXMLHttpRequestsを扱っているため、Axiosはwhatwgによって設定された仕様に制限されます。 :

具体的には、サポートされているタイプは次のとおりです。

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

streamはaxiosでresponseTypeを設定するときに受け入れられますが、これは誤解を招く可能性があります。 XMLHttpRequestsに依存するブラウザを使用しているため、アダプタは暗黙的にxhr.jsになります。 HttpRequestsはサーバー側で作成され、axiosがhttp.jsアダプターを使用できるようにします。次に、Node.jsでResponseTypeとしてstreamを使用できます。

fetch APIを使用することは、ReadableStreamをレスポンスボディタイプとして使用する唯一のソリューションのようです。

3
Joe H