2016-01-20 13 views
38

私はangular2で始まったので、TのObservableを返すようにサービスをセットアップしました。サービスではmap()コールがあり、これらのサービスを使用するコンポーネントはsubscribe()応答を待ちます。これらのシンプルなシナリオでは、私は本当にrxjsを掘り下げる必要はありませんでした。rxjsを使ってリフレッシュトークンを扱う

私は今、次のことを達成したいと思います:リフレッシュトークンでOauth2認証を使用しています。他のすべてのサービスが使用するapiサービスを構築したいと思います。401エラーが返されたときにリフレッシュトークンを透過的に処理します。だから、401の場合は、まずOAuth2エンドポイントから新しいトークンを取り出し、新しいトークンでリクエストを再試行します。上記のコードで

request(url: string, request: RequestOptionsArgs): Promise<Response> { 
    var me = this; 

    request.headers = request.headers || new Headers(); 
    var isSecureCall: boolean = true; //url.toLowerCase().startsWith('https://'); 
    if (isSecureCall === true) { 
     me.authService.setAuthorizationHeader(request.headers); 
    } 
    request.headers.append('Content-Type', 'application/json'); 
    request.headers.append('Accept', 'application/json'); 

    return this.http.request(url, request).toPromise() 
     .catch(initialError => { 
      if (initialError && initialError.status === 401 && isSecureCall === true) { 
       // token might be expired, try to refresh token. 
       return me.authService.refreshAuthentication().then((authenticationResult:AuthenticationResult) => { 
        if (authenticationResult.IsAuthenticated == true) { 
         // retry with new token 
         me.authService.setAuthorizationHeader(request.headers); 
         return this.http.request(url, request).toPromise(); 
        } 
        return <any>Promise.reject(initialError); 
       }); 
      } 
      else { 
       return <any>Promise.reject(initialError); 
      } 
     }); 
} 

、authService.refreshAuthentication()新しいトークンを取得してのlocalStorageに保存します。以下は、約束して、正常に動作コードがあります。 authService.setAuthorizationHeaderは、 'Authorization'ヘッダーを以前に更新されたトークンに設定します。 catchメソッドを見れば、それは(そのリフレッシュトークンの)約束が最終的に(要求の実際の2回目の試みに対して)別の約束を返すという約束を返すことがわかります。私は約束に頼ることなく、これを行うことを試みてきた

request(url: string, request: RequestOptionsArgs): Observable<Response> { 
    var me = this; 

    request.headers = request.headers || new Headers(); 
    var isSecureCall: boolean = true; //url.toLowerCase().startsWith('https://'); 
    if (isSecureCall === true) { 
     me.authService.setAuthorizationHeader(request.headers); 
    } 
    request.headers.append('Content-Type', 'application/json'); 
    request.headers.append('Accept', 'application/json'); 

    return this.http.request(url, request) 
     .catch(initialError => { 
      if (initialError && initialError.status === 401 && isSecureCall === true) { 
       // token might be expired, try to refresh token 
       return me.authService.refreshAuthenticationObservable().map((authenticationResult:AuthenticationResult) => { 
        if (authenticationResult.IsAuthenticated == true) { 
         // retry with new token 
         me.authService.setAuthorizationHeader(request.headers); 
         return this.http.request(url, request); 
        } 
        return Observable.throw(initialError); 
       }); 
      } 
      else { 
       return Observable.throw(initialError); 
      } 
     }); 
} 

コードを上記の私は期待しません:200応答の場合には、それが適切に応答を返します。しかし、401を捕まえると、新しいトークンを正常に取得できますが、サブスクライブすると最終的にレスポンスではなくオブザーバブルが取得されます。これを推測しているImは再試行を行うべき実行されていないObservableです。

rxjsライブラリに取り組むという約束の方法を翻訳するのはおそらく最善の方法ではないと思いますが、「すべてがストリームです」ということを理解することはできませんでした。私はフラットマップ、retryWhenなどを含むいくつかの他のソリューションを試してみました...しかし、didntは遠くになるので、いくつかの助けに感謝します。

答えて

22

あなたのコードを簡単に見てみると、refreshサービスから返されたObservableを平坦化していないことが原因と思われます。

catchオペレータを使用すると、ダウンストリームObserverが違いを知らないように、それが失敗した観測の最後に連結しますObservableを返すことを期待しています。

401以外のケースでは、最初のエラーを再現するObservableを返すことでこれを正しく実行しています。しかし、リフレッシュの場合、Observableを返します。Observablesの代わりに、単一の値が生成されます。

私はあなたがするリフレッシュロジックを変更することをお勧め:

​​

flatMap単一のストリームに中間Observablesを変換します。

+0

ハ:これは動作します:)私はflatMapメソッドを使ってみましたが、明らかに正しい方法ではありませんでした。サンクスポール! Ps:私がrxjsでかなり混乱しているのは、異なる名前のファイルでこれらのメソッドを隠す傾向があることです。 flatMapメソッドが機能するためには、私は "mergeMap"ファイルをインポートしなければなりません... – Davy

+0

@Davy使用しているバージョンを尋ねることができますか? ReactiveXのプロジェクトであれば、まだベータ版になっているので、すべての機能が完了しているにもかかわらず、ドキュメンテーションは少し不足しています。 – paulpdaniels

+0

これはhttps://github.com/ReactiveX/RxJS(「rxjs」npmパッケージ)です。 – Davy

9

RxJの最新リリースでは、flatMapオペレータの名前がmergeMapに変更されました。

関連する問題