2016-12-01 77 views
6

我的使用情况是:RxJs观测量:经过一些异步运行retryWhen请求

  1. 用户从我们的API,它失败,因为JWT到期(作为中HTTPOnly cookie的传递)的请求资产 - API返回401个状态码。
  2. 我们使用refresh_token再次验证它们(不需要用户执行任何操作),以检索新的JWT,并向客户端请求auth0。
  3. 我们将新的JWT发送给我们的API,将其设置为httpOnly cookie来替换已过期的cookie。
  4. 然后,我们要重新原始请求到API的用户在步骤1

我想我的终极版的应用程序中使用与观测量redux-observable。如果你能想到另一种使上述用户流程工作的方式,我会很高兴听到如何。

注意:使用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步林我可能是完全没谱但任何帮助会很好!

回答

6

那么你可能不希望做的一件事是让错误成为顶级流。即使你做了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以上完全是可选的,我把它清理功能。基本上,虽然你想包含内部流的错误,以便它不能停止外部的错误。我不确定您正在使用哪个库,但是您还应该确认它实际上会返回冷库Observable,否则您需要将其包装在defer区块中以便retryWhen正常工作。

+0

真的很好的答案 - 有趣的事情:'.if'和'.let'都没有被记录(http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html) –

+0

有趣,自动生成这些文档的缺陷,我想 – paulpdaniels

+0

感谢这@paulpdaniels,这看起来不错!我还没有机会实施它,但会在我有机会时更新。很高兴将此标记为公认的答案,但直到那时:) – Jbarget