Fetch API を使うときの適切なエラー処理方法
2024/5/10 追記
ありがたいことにこの記事は2024現在もたまにアクセスやいいねがあるのですが、
リクエスト先でリダイレクトが発生するときに追加で注意してほしいことがあるので以下に別記事を書きました。
また、そのうち await 使った版のこの記事も書こうと思います。
TL;DR
- このへん書いてあることをかいつまんだだけです
- URL送りつけるだけだとなぜか伝わらないことがあったので書きました
- Fetch の使用 | Web API | MDN
- Response | Web API | MDN
- Fetch API が 4xx エラーを reject してくれない | 無駄と文化
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 の使用 | Web API | MDN
の 「fetch が成功したかチェックする」の頁に書いてあるエラー処理は
だいたい上記のような感じですね。
ネットワークエラーに遭遇すると fetch() promise は TypeError を返して reject 状態になります。サーバー側の CORS が適切に設定されていない場合も同様です(アクセス権の問題ですけどね) — 一方で例えば 404 はネットワークエラーを構成しません。fetch() が成功したかどうかの明確な判定をするには、プロミスが解決されて、Response.ok (en-US) プロパティが true になっているかなどを確認します。次のようなコードになるでしょう。
と書いてあります。
response.ok
が何を示すのかは Response についての記述の部分に書いてあり、
Response.ok (en-US) 読取専用
レスポンスが成功(200-299 の範囲のステータス)したか否かを通知する boolean 値を含む。
と記述されています。
- Response | Web API | MDN
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.status
やresponse.statusText
などを参照してやる必要がる
ということです
catch で全てのエラー処理をしたいんだが?
- Promise.prototype.catch() | JavaScript | MDN
- throw | JavaScript | MDN
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で結果が出たり、出なかったりしています
上記の方式でエラーを拾えるでしょうか?
fetchAll
ってPHPの話じゃないですか?明確に記載しないですみませんPHP8,1です