DUICUO

Axios はリクエストの再試行をどのように実装しますか?

[[394882]]

「Axiosで重複リクエストをキャンセルする方法」という記事で、AbaoはAxiosで重複リクエストをキャンセルする方法とCancelTokenの動作原理を紹介しました。この記事では、インターセプターまたはアダプターを使用してAxiosでリクエストの再試行を実装する方法を紹介します。では、なぜリクエストの再試行が必要なのでしょうか?これは、リクエストがタイムアウトした場合など、状況によってはリクエストを自動的に再発行して操作を再試行し、対応するタスクを完了させたい場合があるためです。

以下では、Axiosが提供するインターセプターまたはアダプターを使用してリクエストの再試行を実装する方法を紹介します。Axiosのインターセプターやアダプターについてよく知らない方は、まず77.9Kの記事「Axiosプロジェクトから学ぶ価値のあることとは?」を読むことをお勧めします。次に、インターセプターを使用してリクエストの再試行を実装する方法を紹介します。

I. インターセプターベースのリクエスト再試行方式

Axios は Promise ベースの HTTP クライアントであり、HTTP プロトコルはリクエストとレスポンスに基づいています。

そのため、Axios はリクエストとレスポンスをそれぞれ処理するためのリクエスト インターセプターとレスポンス インターセプターを提供しており、それぞれの機能は次のとおりです。

  • リクエスト インターセプター: このタイプのインターセプターの目的は、リクエスト ヘッダーにトークン フィールドを追加するなど、リクエストが送信される前に特定の操作を実行することです。
  • レスポンス インターセプター: このタイプのインターセプターの目的は、レスポンス ステータス コードが 401 の場合にログイン ページに自動的にリダイレクトするなど、サーバー応答を受信した後に特定の操作を均一に実行することです。

Axios でのインターセプターの設定は簡単です。リクエストインターセプターとレスポンスインターセプターは、`axios.interceptors.request` オブジェクトと `axios.interceptors.response` オブジェクトが提供する `use` メソッドを使用して個別に設定できます。

  1. エクスポートインターフェースAxiosInstance {
  2. インターセプター: {
  3. リクエスト: AxiosInterceptorManager<AxiosRequestConfig>;
  4. レスポンス: AxiosInterceptorManager<AxiosResponse>;
  5. };
  6. }
  7.  
  8. エクスポートインターフェースAxiosInterceptorManager<V> {
  9. use(onFulfilled?: (値: V) => V | Promise<V>,
  10. onRejected?: (エラー: any ) => any ): number;
  11. eject(id: number): void;
  12. }

リクエストの再試行機能については、ユーザーが再試行回数だけでなく、再試行の遅​​延も設定できるようにしたいと考えています。リクエストが失敗した場合、リクエストの設定オブジェクトに再試行回数が設定されていれば、Axios は再試行のためにリクエストを再送信します。グローバルなリクエスト再試行を有効にするには、次のコードに示すように、レスポンスインターセプターにリクエスト再試行機能を実装します。

  1. axios.interceptors.response.use( null 、 (err) => {
  2. config = err.config; とします。
  3. if (!config || !config.retryTimes) はPromise.reject(err)を返します
  4. const { __retryCount = 0、retryDelay = 300、retryTimes } = config;
  5. // リクエストオブジェクトの再試行回数を設定する
  6. config.__retryCount = __retryCount;
  7. // 再試行回数を超えたかどうかを確認します
  8. __retryCount >= retryTimes の場合 {
  9. Promise.reject(err)を返します
  10. }
  11. // 再試行回数を増やす
  12. config.__retryCount++;
  13. // 遅延処理
  14. const delay = new Promise((resolve) => {
  15. setTimeout(() => {
  16. 解決する();
  17. }, 再試行遅延);
  18. });
  19. // リクエストを再送信する
  20. 遅延を返しますその後(関数() {
  21. axios(config)を返します
  22. });
  23. });

上記のコードは複雑ではなく、対応する処理フローは次の図に示されています。

インターセプターを使用してリクエストの再試行を実装する方法を紹介した後、リクエストの再試行を実装するためのアダプター ソリューションを紹介します。

II. リクエスト再試行のアダプタ実装

Axios は、ブラウザと Node.js 環境の両方をサポートできるアダプタを導入しました。ブラウザの場合は XMLHttpRequest API をラップして HTTP リクエストを送信し、Node.js の場合は Node.js の組み込み http および https モジュールをラップして HTTP リクエストを送信します。

「Axiosでリクエストデータをキャッシュする方法」の記事では、デフォルトのAxiosアダプターを拡張することでリクエストデータのキャッシュを実装する方法を説明しました。同様のアプローチで、デフォルトのAxiosアダプターを拡張することでリクエストの再試行を実装することもできます。

デフォルトのアダプターを拡張する方法を紹介する前に、lib/adapters/xhr.js ファイルで定義されている、Axios に組み込まれている xhrAdapter を見てみましょう。

  1. // lib/adapters/xhr.js
  2. module.exports =関数xhrAdapter(config) {
  3. 新しいPromiseを返します(関数dispatchXhrRequest(resolve, refuse) {
  4. var requestData = config.data;
  5. var requestHeaders = config.headers;
  6.  
  7. var request = 新しい XMLHttpRequest();
  8. // コードの大部分は省略されています
  9. var fullPath = buildFullPath(config.baseURL, config.url);
  10. リクエストを開きます(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true );
  11. //リクエストタイムアウトをMS設定する
  12. リクエストのタイムアウト = config.timeout;
  13.  
  14. //準備状態リッスンする
  15. request.onreadystatechange =関数handleLoad() { ... }
  16.  
  17. // リクエストを送信する
  18. リクエストを送信します。(リクエストデータ)
  19. });
  20. };

xhrAdapter は明らかに関数オブジェクトであり、config パラメータを受け取り、Promise オブジェクトを返します。内部的には、xhrAdapter は最終的に XMLHttpRequest API を使用して HTTP リクエストを送信します。リクエストの再試行機能を実装するには、高階関数を用いて xhrAdapter の機能を拡張することを検討できます。

2.1 retryAdapterEnhancer関数を定義する

ユーザーがリクエストの再試行機能をより柔軟に制御できるように、次の 2 つのパラメータをサポートする `retryAdapterEnhancer` 関数を定義しました。

  • アダプター: 事前に拡張された Axios アダプター オブジェクト。
  • options: それぞれ異なる機能を構成するために使用される 2 つのプロパティをサポートするキャッシュされた構成オブジェクト。
  • times: リクエストが再試行される回数をグローバルに設定します。
  • delay: グローバル リクエストの遅延時間をミリ秒単位で設定します。

`retryAdapterEnhancer` 関数のパラメータを理解した後、その実装を見てみましょう。

  1. 関数retryAdapterEnhancer(アダプタ, オプション) {
  2. const { times = 0, delay = 300 } = オプション;
  3.  
  4. 非同期を返す(config) => {
  5. const { retryTimes = 回、 retryDelay = 遅延 } = config;
  6. __retryCount = 0 とします。
  7. const リクエスト = 非同期 () => {
  8. 試す {
  9. アダプタ(config)を待機して戻ります
  10. } キャッチ (エラー) {
  11. // 再試行するかどうかを決定する
  12. 再試行回数が __retryCount >= 再試行回数の場合
  13. Promise.reject(err)を返します
  14. }
  15. __retryCount++; // 再試行回数を増やす
  16. // 遅延処理
  17. const delay = new Promise((resolve) => {
  18. setTimeout(() => {
  19. 解決する();
  20. }, 再試行遅延);
  21. });
  22. // リクエストを再送信する
  23. 遅延を返しますその後(() => {
  24. request()を返します
  25. });
  26. }
  27. };
  28. request()を返します
  29. };
  30. }

上記のコードは複雑ではありません。コア処理ロジックは次の図に示されています。

2.2 retryAdapterEnhancer関数の使用

2.2.1 Axiosオブジェクトを作成し、アダプタオプションを設定する

  1. 定数 http = axios.create ( {
  2. ベースURL: "http://localhost:3000/" ,
  3. アダプター: retryAdapterEnhancer(axios.defaults.adapter, {
  4. 再試行遅延: 1000,
  5. })、
  6. });

2.2.2 HTTPオブジェクトを使用したリクエストの送信

  1. // リクエストが失敗した場合は再試行しない
  2. 関数requestWithoutRetry() {
  3. http.get( "/users" );
  4. }
  5.  
  6. // リクエストが失敗した場合は再試行する
  7. 関数requestWithRetry() {
  8. http.get( "/users" , { 再試行回数: 2 });
  9. }

これで、xhrAdapter を拡張して Axios リクエストのリトライ機能を実装する方法の説明は終わりです。完全なサンプルコードは非常に長大なので、ここでは具体的なコードは掲載しません。興味のある方は、以下のアドレスにアクセスしてサンプルコードをご覧ください。

  • 完全なサンプルコード:
  • https://gist.github.com/semlinker/979ebc659abacea7aa6c0c44af070afe

ここでは、リクエストの再試行の Axios の例を実行した結果を見てみましょう。

III. 要約

この記事では、Axios でリクエストの再試行を実装する方法について説明します。この記事で定義した retryAdapterEnhancer 関数またはレスポンスインターセプターに基づいて、リクエストの再試行機能を簡単に拡張できます。

Axiosは優れたオープンソースプロジェクトであり、多くの貴重な教訓を学ぶことができます。Axiosの内部HTTPインターセプター、HTTPアダプターの設計と実装、そしてCSRF攻撃の防御方法にご興味をお持ちの方は、77.9Kの記事「Axiosプロジェクトから学ぶべき価値とは?」をお読みください。

IV. 参考資料

  • Github - axios-extensions
  • Axios で重複したリクエストをキャンセルするにはどうすればよいですか?
  • Axios はリクエストデータをどのようにキャッシュしますか?
  • 77.9K Axios プロジェクトから得られる貴重な教訓は何でしょうか?