8

私のユースケースは次のとおりです。

  1. JWT の期限切れ (httpOnly Cookie として渡される) が原因で失敗する API からのユーザー リクエスト アセット - API は 401 ステータス コードを返します。
  2. クライアントから auth0 へのリクエストで新しい JWT を取得するために、refresh_token を使用して (ユーザーが何もせずに) 再びそれらを認証します。
  3. その新しい JWT を API に送信して、期限切れの Cookie を置き換える httpOnly Cookie として設定します。
  4. 次に、ステップ 1 でユーザーが API に対して行った元のリクエストを再試行します。

Redux アプリ内でredux-observableを使用して Observables を使用しようとしています。上記のユーザー フローを機能させる別の方法を考えられる場合は、その方法を教えていただければ幸いです。

注意。使用していますrxjs V5

export const fetchAssetListEpic = (action$, store) => {
  return action$.ofType('FETCH_ASSET_LIST')
  .switchMap( action => {
    const options = {
      crossDomain: true,
      withCredentials: true,
      url: uriGenerator('assetList', action.payload)
    };
    return ajax(options);
  })
  .map(fetchAssetListSuccess)
  .retryWhen(handleError)
  .catch(redirectToSignIn);
};

function handleError(err) {
  return (err.status === 401) ? 
  /* Authenticate here [Step 2] */
  /* Send new JWT to API [Step 3] */
  /* If successful make original request again [Step 4] */
  :
  Observable.throw(err);
}
  
function redirectToSignIn() {
  /*I will redirect here*/
}

これまでのところ、ステップ 1、2、および 3 を完了することができましたが、ステップ 4 を追加する方法がわかりません。完全に的外れかもしれませんが、どんな助けも素晴らしいでしょう!

4

1 に答える 1

8

おそらくやりたくないことの 1 つは、エラーが最上位ストリームに到達するのを許可することです。実行してもcatch、トップレベルのストリームを効果的に殺しています。したがって、リダイレクトが、react-router などを介してソフト リダイレクトではなくハード リダイレクトを実行しない限り、このエピックを使用することはできなくなります。

したがって、ほとんどのロジックを 内にカプセル化する必要があると言えますswitchMap

function withAuthorizedFlow(source) {
  return source
    .map(fetchAssetListSuccess)
    // retryWhen takes a callback which accepts an Observable of errors
    // emitting a next causes a retry, while an error or complete will
    // stop retrying
    .retryWhen(e => e.flatMap(err => 
      Observable.if(
        // Returns the first stream if true, second if false
        () => err.status === 401,
        reauthenticate, // A stream that will emit once authenticated
        Observable.throw(err) // Rethrow the error
      ))
    )
    .catch(redirectToSignIn);
}

/** Within the epic **/
.switchMap(({payload}) => {
  const options = {
    crossDomain: true,
    withCredentials: true,
    url: uriGenerator('assetList', payload)
  };

  // Invoke the ajax request
  return ajax(options)
    // Attach a custom pipeline here
    // Not strictly necessary but it keeps this method clean looking.
    .let(withAuthorizedFlow);
})

上記の使用letは完全にオプションです。関数をクリーンアップするために使用しました。基本的には、外側のストリームを停止できないように、エラーを内側のストリームに含めたいと考えています。どのajaxライブラリを使用しているかはわかりませんが、実際にコールドを返すことも確認する必要があります。それ以外の場合は、ブロックObservableでラップして動作させる必要があります。deferretryWhen

于 2016-12-01T18:47:33.093 に答える