したいこと
Viewに配置されているボタンをクリックしたら、非同期でサーバー処理を行いその処理の成否でjavascript上で処理を分岐する。
背景
開発運用中のシステムに機能追加を行う場面でのお話
実装していくよ〜
まずは既存コードから探してみる
既存のコードの中にfetchを使用して今回したいことと同じことをしている箇所を発見したので、そのまま倣ってみる。
Button.onclick = () => {
const url = 'xxxx.com'
fetch(url, {
method: 'POST',
headers: {〜〜〜〜}
})
.then(() => {
console.log('通信成功');
// 成功時の処理
})
.catch(() => {
console.log('通信失敗');
// 失敗時の処理
});
}
このコードを読んで、サーバー側で例外が発生したときに、サーバーエラーレスポンス(500~599)で返すので、その際は catch に入って失敗時の処理ができると予想した。
ステータス500で返しても catch 入らなくね?
となった。
fetch を使うのはほぼ初めてで予想と違う結果に戸惑った。レスポンスの返し方が悪いのか、返している値が悪いのかと、30分くらいガチャガチャ実験していた。
こういうときは基本に立ち返るべし!
と、公式リファレンスを読んでみると、冒頭でいきなり
fetch() のプロミスはネットワークエラーが発生した場合(普通は権限の問題があったときなど)のみ拒否されます。 fetch() のプロミスは HTTP エラー(404 など)では拒否されません。代わりに、 then() ハンドラーで Response.ok や Response.status プロパティをチェックする必要があります。
まさにこれやん!
HTTPエラーでは拒否されないと書いてあるので、いくらステータスエラーを返してもcatchに入ってくれないようだ。だが、そもそもやりたかったのは分岐処理だ。レスポンスからサーバー側のエラーを検知できれば問題なし。それもココで書いてある Response.ok でその検知ができそうだ。
Button.onclick = () => {
const url = 'xxxx.com'
fetch(url, {
method: 'POST',
headers: {〜〜〜〜}
})
.then((response) => {
console.log('通信成功');
if(response.ok) {
// 成功時の処理
console.log('処理成功');
} else {
// 失敗時の処理
console.log('処理失敗');
}
})
.catch(() => {
console.log('通信失敗');
});
}
なるほど!これでサーバー側の例外を検知することができるようになった!
おわりに
既存コードにあったとしても、知らないことについては、まず公式ドキュメントなどを読もう。
参考