やりたいこと
Angular10のHttpClinetでAPIからデータを取得し、
その取得結果を待ってからビューの描写を開始したいです。
そこで、以下を参考にして、
HttpClinetを利用してAPIからデータを取得するサービス(ScoresClientService)と、
Resolveインターフェースを実装したサービス(DetailResolverService)を作成して、
コンポーネントのルーティング前にデータ取得処理を実行するようにしました。
問題
正常時は、意図した通り、データ取得を待ってからビューを描写出来ました。
しかし、HTTPエラー受信時は、処理出来ずに何も描写出来なくなってしまいました。
コンポーネント側で何も処理出来ていない状態です。
発生しているエラー
Google ChromeのDevToolのConsoleに以下のエラーが出ています。
一つ目は500エラーを受信したというメッセージなのであまり関係ないと思います。
二つ目のエラーが本事象の直接原因だと思います。
調べても分からなかったのですが、
HttpClinetはエラーの場合、HttpErrorResponseを受信するので、
それを扱えていないのではないかと推測しています。
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
core.js:4197 ERROR Error: Uncaught (in promise): HttpErrorResponse: {"headers":{"normalizedNames":{},"lazyUpdate":null},"status":500,"statusText":"Internal Server Error","url":"http://localhost:4200/api/scores","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://localhost:4200/api/scores: 500 Internal Server Error","error":null} at resolvePromise (zone.js:832) at resolvePromise (zone.js:784) at zone.js:894 at ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:27425) at ZoneDelegate.invokeTask (zone.js:420) at Zone.runTask (zone.js:188) at drainMicroTaskQueue (zone.js:601) at ZoneTask.invokeTask [as invoke] (zone.js:507) at invokeTask (zone.js:1671)
コード
HttpClinetを利用してAPIからデータを取得するサービス(ScoresClientService)
TypeScript
1@Injectable({ 2 providedIn: 'root' 3}) 4export class ScoresClientService { 5 6 constructor(private httpClient: HttpClient) { } 7 8 post(claimNumber: string): Observable<Scores> { 9 // HTTPリクエストの各情報セット 10 const scoresUri = environment.scores_url; 11 const params = { claimNumber: claimNumber }; 12 const headers = { 'Content-Type': 'application/json' }; 13 14 // スコア詳細を取得し、取得結果を呼び出し元に返す 15 return this.httpClient.post<Scores>(scoresUri, params, { headers: headers }); 16 } 17}
Resolveインターフェースを実装したサービス(DetailResolverService)
TypeScript
1@Injectable({ 2 providedIn: 'root' 3}) 4export class DetailResolverService implements Resolve<Scores> { 5 6 constructor(private client: ScoresClientService) { } 7 8 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Scores> { 9 const claimNumber = route.paramMap.get('claimNumber'); 10 return this.client.post(claimNumber); 11 } 12}
ルーティング設定(app-routing.module.tsの一部抜粋)
TypeScript
1const routes: Routes = [ 2 { 3 path: 'detail/:claimNumber', 4 component: DetailComponent, 5 resolve: { 6 detail: DetailResolverService 7 } 8 } 9];
コンポーネント(DetailComponentの一部抜粋)
TypeScript
1constructor(private route: ActivatedRoute) 2 ) { } 3 4this.route.data.subscribe( 5 response => {(省略) 6 }, error => {(省略)
確認したこと
- DetailResolverServiceを使わないで、コンポーネントから直接ScoresClientServiceを呼び出せば、
HTTPエラー受信時も正常に処理できる。
(その代わり、データ取得を待ってから描写を開始できなくなる)
- DetailResolverServiceはScoresClientServiceからObservableを受け取っている。
以下のようにDetailResolverServiceを書き換えると、console.log(response)でObservableのオブジェクトを出力できる。
(try catchに意味はないです。あわよくばcatchしてエラーページに飛ばせないか考えましたが、出来ませんでした)
- HTTPエラー500以外のエラー(400)でも本事象が発生すること。
TypeScript
1@Injectable({ 2 providedIn: 'root' 3}) 4export class DetailResolverService implements Resolve<any> { 5 6 constructor(private client: ScoresClientService, private router: Router) { } 7 8 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> { 9 const claimNumber = route.paramMap.get('claimNumber'); 10 try { 11 const response = this.client.post(claimNumber); 12 console.log('受信確認'); 13 console.log(response) 14 return response; 15 } catch(e) { 16 this.router.navigate(['/list/error']); 17 } 18 } 19}
以上です。
何か気づくことがあればご教授下さい。
理想はObservableをDetailComponentに渡せれば良いのですが、
出来なければ、DetailResolverServiceでエラーハンドリングして、
HTTPエラー受信時にはエラーページに飛ばすでも良いと思っていますが、
その方法も分からなかったので、もし分かる方がいらっしゃればご教授頂きたいです。
宜しくお願い致します。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。