web-dev-qa-db-ja.com

angular 6でHTTPリクエストを再試行する

インターセプターを使用して、すべての要求のHTTP応答に基づいてエラーメッセージを表示します。

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const customReq = request.clone({
        //headers: request.headers.set('app-language', 'en')
    });
    return next
        .handle(customReq).pipe(
            tap((ev: HttpEvent<any>) => {
                if (ev instanceof HttpResponse) {
                    // processing request
                }
            }),
            catchError(response => {
                if (response instanceof HttpErrorResponse) {
                    switch (response.status) {
                        case 0:
                            // server API connection error show
                            break;
                        case 403:
                            // error Token Invalid and Redirect to logout
                            break;
                        case 401:
                            // error Token Invalid and Redirect to logout
                            break;
                        case 502:
                            // Bad gateway error
                            break;
                        case 500:
                            // internal server error
                            break;
                    }
                }
                // return next.handle(request);
                return observableThrowError(response);
            })
        );
}

私のプロジェクトでは、Webサーバーが1秒間使用できない場合があり、500エラーコードを返します。エラーを受け取った直後にWebアプリにエラーメッセージを表示させたくないので、1秒程度の遅延でリクエストを数回再試行したいと思います。

私はすでにrxjsの再試行を試みました:

...
.handle(customReq).pipe(retry(5),
...

遅延がないため、役に立ちません。この回答に基づいて 遅延と試行の制限付きでRXjs RetryWhenを作成する方法

再試行しました

.handle(customReq).pipe(
    tap((ev: HttpEvent<any>) => {
        if (ev instanceof HttpResponse) {
            console.log('###processing response', ev, this.location);
        }
    }),
    retryWhen(error => {
        return error
            .flatMap((error: any) => {
                if (error.status  == 400) {
                    return Observable.of(error.status).delay(1000);
                }
                if (error.status  == 0) {
                    return observableThrowError(error).delay(1000);
                }
                return observableThrowError(error);
            })
            .take(5)
            .concat(observableThrowError(error));
    }),

しかし、期待どおりに機能せず、if条件の内側に移動しません。

6
Amir Khademi

コードにはいくつかのエラーがあります。

  1. error変数をシャドウイングしています-最初はエラーストリームであり、次にエラーオブジェクトです。
  2. observableThrowErrordelayを使用しても効果はありません。エラーは、エラーを処理する演算子を除くすべての演算子をバイパスします。
  3. "pipe(operator())"スタイル演算子とプロトタイプスタイル演算子.operator()を混合しています。

私はいくつかの変更を提案しました:

.handle(customReq).pipe(
    tap((ev: HttpEvent<any>) => {
        if (ev instanceof HttpResponse) {
            console.log('###processing response', ev, this.location);
        }
    }),
    retryWhen(errors => errors
        .pipe(
            concatMap((error, count) => {
                if (count < 5 && (error.status == 400 || error.status == 0)) {
                    return Observable.of(error.status);
                }

                return observableThrowError(error);
            }),
            delay(1000)
        )
    ),

主な変更点は、オブザーバブルのサブスクライブ解除に主に役立つconcatMap operatorを使用する代わりに、takeの2番目の引数でエラーカウントを追跡することです。代わりにエラーをスローする必要があります。

10
m1ch4ls

次のブログ投稿では、失敗したHTTP要求を再試行する方法について説明しています。また、再試行の処理方法に関するさまざまな戦略も提供します。

https://blog.angularindepth.com/retry-failed-http-requests-in-angular-f5959d486294?source=activity---post_recommended_rollup

1
Trafalgar