如何通过rxjs尽早逃离捕获链?

时间:2017-06-15 16:21:16

标签: javascript error-handling rxjs reactive-programming redux-observable

我创建了一个包装器,用于使用身份验证标头访问'rxjs / observable / dom / ajax'函数。那部分没问题。

export const authjax = {
  create: urlOrRequest => ajax(typeof urlOrRequest === 'string'
    ? {url: urlOrRequest, headers: authHeader()} : _.merge({}, urlOrRequest, {headers: authHeader()})
  ),
  get: (url, headers = {}) => ajax.get(url, {...headers, ...authHeader()}),
  post: (url, body = {}, headers = {}) => ajax.post(url, body, {...headers, ...authHeader()}),
  put: (url, body = {}, headers = {}) => ajax.put(url, body, {...headers, ...authHeader()}),
  patch: (url, body = {}, headers = {}) => ajax.patch(url, body, {...headers, ...authHeader()}),
  getJSON: (url, headers = {}) => ajax.getJSON(url, {...headers, ...authHeader()})
};

所以,这被用来取代ajax。这是一个在史诗中使用的例子。

export const getBatchesEpic = (action$, store) =>
  action$.ofType(actions.GET_BATCHES)
    .switchMap(action => {
      const {paginate, refresh} = action;
      const paginatorNext = _.get(store.getState(), 'manager.paginator.batches.next');
      const usePaginatorNext = paginatorNext && paginate && !refresh;
      return authjax.get(usePaginatorNext ? paginatorNext : `${API_URL}/batches/`)
        .concatMap(({response}) => {
          const incompleteBatches = response.results.filter(batch => !batch.completed);
          const checkBatchActions = incompleteBatches.map(batch => checkBatch(batch.id));
          return [
            {type: actions.BATCHES_RECEIVED, data: response, next: response.next, paginate},
            ...checkBatchActions
          ];
        })
        .catch(error => Observable.of({type: actions.GET_BATCHES_ERROR, error})
      );
    });

现在,我正处于尝试仅使用authjax.get方法进行简单测试传递的第一阶段。我希望服务器的401响应被authjax捕获,并且authjax返回注销操作,以及取消任何后续的链接方法。

这是我authjax.get的最新尝试。它适用于成功的ajax响应,以及非401 ajax响应。当它击中401时,它不会返回任何内容,甚至是退出操作。

export const authjax = {
  create: urlOrRequest => ajax(typeof urlOrRequest === 'string'
    ? {url: urlOrRequest, headers: authHeader()} : _.merge({}, urlOrRequest, {headers: authHeader()})
  ),
  get: (url, headers = {}) => {
    const call = ajax.get(url, {...headers, ...authHeader()});

    return call.catch(error => {
      if (_.get(error, 'status') === 401) {
        console.log('401!!!', Observable.of({type: actions.LOGOUT}));
        return Observable.of({type: actions.LOGOUT}).ignoreElements();
      }
      return call;
    });

  },
  post: (url, body = {}, headers = {}) => ajax.post(url, body, {...headers, ...authHeader()}),
  put: (url, body = {}, headers = {}) => ajax.put(url, body, {...headers, ...authHeader()}),
  patch: (url, body = {}, headers = {}) => ajax.patch(url, body, {...headers, ...authHeader()}),
  getJSON: (url, headers = {}) => ajax.getJSON(url, {...headers, ...authHeader()})
};

我正在阅读rxjs文档,但发现假设您永远不需要切换或取消流中的流。我知道有些选项我可以在Epic中处理更多内容,但我希望authjax能够处理自己的身份验证问题,因此我可以使用相同的身份验证将其用作跨多个应用程序的导入。

1 个答案:

答案 0 :(得分:0)

这是我现在提出的答案。

export const wrapAjax = ({method, args = {}}) => {
  const headers = {...args.headers || {}, ...authHeader()};

  const call = method
    ? ajax[method](..._.values(_.omit(args, ['headers'])), headers)
    : ajax(_.merge({}, args, {headers}));

  return call.catch(error => {
    if (_.get(error, 'status') === 401) {
      return Observable.throw({...error, action: {type: actions.AUTH_401, error}}).ignoreElements();
    }
    return call;
  });
};

如果状态为401,则会停止任何链式方法,并且会触及任何后续的catch语句。史诗中的catch语句遗憾地必须分派返回的action属性。没有激怒,但这就是我现在最终继续前进的方式。