如何从错误处理程序分派操作并立即中断 redux-observable 中 Observable 链的其余部分?

How to dispatch actions from an error handler and immediately break the rest of the Observable chain in redux-observable?

为了处理 401 个未经授权的请求,我尝试用错误处理程序包装我所有的 api 请求:

const apiGet (props) = ajax({
  headers,
  method: 'GET',
  ...props
}).catch(res => {
  if (res.status === 401)
    return Observable.of(unauthorizedAction();
  else
    return Observable.throw(res);
});

理想情况下,我可以按以下方式使用它,知道 401 会触发 unauthorizedAction(),而 500 会由 handleOtherErrors 处理。

action.ofType(SOME_ACTION) => 
  apiGet(something)
    .map(res => doSomethingWithResponse(res))
    .catch(handleOtherErrors);

但是,通过上面的设置,当我收到 401 响应时,问题就出现了。 errorHandler returns unauthorizedAction 如预期的那样,但随后它继续映射操作并尝试对响应做一些事情,而不是分派该操作并终止 Observable 链。

所以,我的问题是,我怎么能在我的错误处理程序中做这样的事情?

.catch(res => {
  if (res.status === 401)
    // Dispatch an action, but stop the rest of the chain
  else
    return Observable.throw(res);
}).map(...restOfChain)
  .catch(additionalErrorHandlerForNon401);

运算符是一连串的 Observables,它们不知道之前或之后的运算符如何或做什么。可以创建您自己的自定义运算符系列来拥有这样的知识和能力,但我不推荐这样做,因为它违背了传统的 RxJS 模式。

相反,您可以传递将使用 map 应用的结果选择器。

// provides a default `resultSelector` that is basically a noop
const apiGet = (props, resultSelector = res => res) =>
  ajax({ headers, method: 'GET', ...props })
    .map(res => resultSelector(res))
    .catch(res => {
      if (res.status === 401)
        return Observable.of(unauthorizedAction());
      else
        return Observable.throw(res);
    });

然后可以这样使用:

apiGet(something, res => doSomethingWithResponse(res))
  .catch(handleOtherErrors)

当动作创建者具有与 resultSelector 相同的签名时,您甚至可以直接传递它 as-is

apiGet(something, doSomethingWithResponse)
  .catch(handleOtherErrors)