💥

Fetch API を使うときの適切なエラー処理方法

2021/04/08に公開
3

2024/5/10 追記

ありがたいことにこの記事は2024現在もたまにアクセスやいいねがあるのですが、
リクエスト先でリダイレクトが発生するときに追加で注意してほしいことがあるので以下に別記事を書きました。
また、そのうち await 使った版のこの記事も書こうと思います。

https://zenn.dev/junki555/articles/9ea9bd54aa1ddc

TL;DR

Fetch API を使うときの簡単なエラー処理

まずは簡単なサンプルコードです。
エラーの処理はサービスごとにそれぞれやるべきことがあると思うので、
今回のサンプルコードでは一律 console.error() だけにしてあります。

fetch('http://example.com/movies.json', {
    method: 'GET'
  })
  .then(response => {
    if (!response.ok) {
      console.error('サーバーエラー');
    }
    // ここに成功時の処理を記述
  })
  .catch(error => {
    console.error('通信に失敗しました', error);
  });

の 「fetch が成功したかチェックする」の頁に書いてあるエラー処理は
だいたい上記のような感じですね。

ネットワークエラーに遭遇すると fetch() promise は TypeError を返して reject 状態になります。サーバー側の CORS が適切に設定されていない場合も同様です(アクセス権の問題ですけどね) — 一方で例えば 404 はネットワークエラーを構成しません。fetch() が成功したかどうかの明確な判定をするには、プロミスが解決されて、Response.ok (en-US) プロパティが true になっているかなどを確認します。次のようなコードになるでしょう。

と書いてあります。
response.ok が何を示すのかは Response についての記述の部分に書いてあり、

Response.ok (en-US) 読取専用
レスポンスが成功(200-299 の範囲のステータス)したか否かを通知する boolean 値を含む。

と記述されています。

Fetch API の Promise reject だけを見るのではダメなのか?

Fetch API は Promise を返すので
一見 catch さえしてあればエラー処理ができそうではあります。
しかし、引用に書いたように Fetch API はネットワークエラーに遭遇したときに reject になります。
逆にいえば、ネットワークエラーにはならずにサーバーエラー(HTTP 5xx など)の場合は
Promise は reject にならずに処理されるのです。

まとめると Fetch API は

  • ネットワーク通信に失敗したときに catch が動く
  • リクエストが失敗したか(response.status が 200-299 の範囲でなかったか)どうかは response.ok を確認してやる必要がある
  • !response.ok のとき、さらに詳細な情報が必要な場合は適宜 response.statusresponse.statusText などを参照してやる必要がる

ということです

catch で全てのエラー処理をしたいんだが?

Promise の中で throw new Error() してやればその時点で catch してくれますね。
なのでさっきのサンプルコードならこんな感じになります。

fetch('http://example.com/movies.json', {
    method: 'GET'
  })
  .then(response => {
    if (!response.ok) {
      console.error('response.ok:', response.ok);
      console.error('esponse.status:', response.status);
      console.error('esponse.statusText:', response.statusText);
      throw new Error(response.statusText);
    }
    // ここに成功時の処理を記述
  })
  .catch(error => {
    // ネットワークエラーでも !response.ok でもここで処理できる
    console.error('エラーが発生しました', error);
  });

簡単ですね。今回はここまでです。

Discussion

と

今、fetchAllで結果が出たり、出なかったりしています
上記の方式でエラーを拾えるでしょうか?

と

明確に記載しないですみませんPHP8,1です