2016-04-15 15 views
7

Angular2のHTTPクラスで認証失敗(401)を返すことができるサーバーを呼び出したいとします。リクエストでエラーをキャッチしてモーダルを開き、RxJSでモーダルが閉じるときに再試行する方法

要求の流れがそのようになっているはず

ユーザーがmyService.getSomething()を使用してサーバーに要求を出し
    • サーバーが401を返す場合)(
    • を購読:開きますユーザーに彼の資格情報を求めるモーダルウィンドウ。
    • ユーザーが正常にアプリケーション
    • モーダルが閉じに再度ログインし
    • は は(()myService.getSomething()。サブスクライブ)

    ここで最初の要求を再試行する必要があり、コールバックで

  • コールバックを実行し私は一瞬のために持っている:

    export class MyService { 
        // ... 
        public getSomething(): Observable<Response> { 
         return this.http.get(url, options).catch((res: any, ob: any) => this.errorHandler(res, ob)); 
        } 
    
        public errorHandler(res: Response, ob: Observable<any>): Observable<Response> { 
         if (res.status === 401) { 
          this.modalService.open(new ModalConfig({ 
           content: LoginModalComponent, 
           close:() => { ob.retry(1); console.log("weow") } // <=close is the callback that should initiate the retry action on the initial request. 
          })); 
         } 
         else { 
          return Observable.throw(res.json()); 
         } 
        } 
    } 
    

    doSomethingの()は、そのように使用されている:doSomething().map((r) => r.json()).subscribe((r) => ....)

    更新1

    @Thierry Templierのソリューションのように自分のコードを変更しました。

    private errorHandler(res: Response, ob: Observable<any>): Observable<Response> { 
        if (res.status === 401) { 
         let closedSubject = new Subject(); 
         this.modalService.open(new ModalConfig({ 
          content: LoginModalComponent, 
          close:() => { closedSubject.next(res);} // I also tried .complete(), .next(null), .next(true), .next(false) 
         })); 
         return ob.retryWhen(() => closedSubject); 
        } 
        else { 
         return Observable.throw(res.json()); 
        } 
    } 
    

    悲しいことに、それでもまだ動作しません。 retryWhenはすぐに実行され、closedSubject.next()が呼び出されるのを待機しません。したがって、オリジナルのObservable(getSomething()関数)をスパムする無限ループを開始します。

    アップデート2

    私は無限ループを示すためにplunkerを作成:

    https://plnkr.co/edit/8SzmZlRHvi00OIdA7Bga

    警告:plunkerを実行すると、文字列 '試験'

    を使用してコンソールをスパムします更新3

    ティエリーの正解に続いて、ソースフィールドが保護されているので、ソースフィールドを使用しない方法を見つけようとしました。 rxjsのissue trackerにフィールドを公開するように依頼した後、寄稿者はより良い解決策を提案しました。

    public get(url: string, options?: RequestOptionsArgs): Observable<Response> { 
        return super.get(url, options).retryWhen((errors: any) => this.errorHandler(errors)); 
    } 
    private errorHandler(errors): any { 
        return errors.switchMap((err) => { 
         if (err.status === 401) { 
          let closedSubject = new Subject(); 
          this.modalService.open(new ModalConfig({ 
           content: LoginModalComponent, 
           close:() => { closedSubject.next(err); } 
          })); 
          return <any>closedSubject; 
         } 
         else { 
          return Observable.throw(err.json()); 
         } 
        }); 
    } 
    

    私はソースフィールドを使用する必要がないので、.catchの使用は避けてください。

  • +0

    これですべての作業は完了ですか? – user3743222

    +0

    はい、動作します。 –

    答えて

    7

    私はあなたにも401エラーが発生した場合における観察可能な何かを返す必要があることだと思う:https://jaxenter.com/reactive-programming-http-and-angular-2-124560.html

    public errorHandler(res: Response, ob: Observable<any>): Observable<Response> { 
        if (res.status === 401) { 
         let closedSubject = new Subject(); 
         this.modalService.open(new ModalConfig({ 
          content: LoginModalComponent, 
          close:() => { 
           closedSubject.next(); 
         })); 
         return ob.retryWhen(() => closedSubject); 
        } 
        else { 
         return Observable.throw(res.json()); 
        } 
    } 
    

    は、より多くの詳細については、こちらの記事を参照してください。

    編集

    問題はcatchコールバックの2番目のパラメータが観測源ではないということです。このソースそのsourceプロパティの値を観測可能な対応:https://plnkr.co/edit/eb2UdF9PSMhf4Dau2hqe?p=preview

    return ob.source.retryWhen((errors) => closedSubject); 
    

    は作業plunkrを参照してください。

    +0

    私はこれが答えに近いと感じますが、それでも動作しません。サーバが401を投げると、errorHandlerは無限ループに入ります。モーダルが閉じるのを待たずに要求を再試行します。 –

    +1

    あなたのログインモーダルで何をしたのか分かりませんが、再度実行する前にリクエストに何かを設定する必要があると思います。この理由から、私は再試行を使わず、URLと更新されたオプション(例えば 'Authorization'ヘッダ)に基づいてリクエストを再実行するべきだと考えています... –

    +0

    問題はretryWhenが直ちに解決されるということです。 closeSubject.next()が呼び出されるのを待っていません。 –

    関連する問題