← Angular コース
47. HTTPエラーへの備え — catchError と status
通信はサーバーの障害やネットワークの切断でかならず失敗することがあります。RxJSの catchError オペレーターを pipe に挟むと、エラーが起きたときの代替処理を流れの中に組み込めます。catchError(() => of([])) のように of で代替値を返せば、流れはエラーで止まらず「空の結果が届いた」ことにして画面を守れます。
エラーの内容は HttpErrorResponse で受け取れ、status プロパティで原因を見分けます。0 はサーバーに到達すらできなかったネットワーク断、404 はリソースが見つからない、500 はサーバー内部のエラーです。実務では status に応じて「通信環境を確認してください」「データが見つかりません」のようにユーザーへの通知メッセージを出し分けます。
つまずきやすいのは、エラー処理を「あとで足すもの」と考えてしまうことです。エラーは必ず起きるものとして、読み込み中・成功・失敗の3状態を最初から画面の設計に含めましょう。また catchError を pipe のどこに置くかでも動きが変わります。リクエストの直後に置けばそのリクエストの失敗だけを処理でき、流れ全体の最後に置けばまとめて処理できます。
サンプルコード(フレームワーク環境が必要なため表示のみ)
import { Component, inject, signal } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
import { catchError, of } from 'rxjs';
type Order = { id: number; total: number };
@Component({
selector: 'app-order-history',
template:
'@if (message()) { <p>{{ message() }}</p> }' +
'@for (o of orders(); track o.id) { <p>{{ o.total }} 円</p> }',
})
export class OrderHistoryComponent {
private http = inject(HttpClient);
message = signal('');
orders = toSignal(
this.http.get<Order[]>('/api/orders').pipe(
// エラー時は status を見て通知を出し、代替値(空配列)で流れを続ける
catchError((err: HttpErrorResponse) => {
if (err.status === 0) {
this.message.set('通信環境を確認してください');
} else if (err.status === 404) {
this.message.set('注文データが見つかりません');
} else {
this.message.set('サーバーでエラーが発生しました');
}
return of([] as Order[]);
})
),
{ initialValue: [] as Order[] }
);
}
サンプルコードで身につける(5本) →
学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。
公式ドキュメントで詳しく ↗