Как я могу избежать цепочки перехвата с помощью rxjs?

Я сделал оболочку для доступа к функциям 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. Я хочу, чтобы authjax перехватывал 401 ответ с сервера, и чтобы 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 мог позаботиться о своих собственных проблемах аутентификации, чтобы я мог использовать его как импорт в несколько приложений, использующих одну и ту же аутентификацию.


person Sally    schedule 15.06.2017    source источник
comment
Мне пришлось сделать то же самое пару раз - отменить все ожидающие запросы concatMap на основе результата внутри concatMap. Недавно я ответил на аналогичный вопрос: любая точка"> stackoverflow.com/questions/44496395/   -  person Julia Passynkova    schedule 15.06.2017
comment
zip у меня не сработал, потому что я должен завершить все, что возвращается из authjax, прежде чем вернуть его, поэтому я не могу добавить следующие связанные методы в zip. Я попробовал .ignoreElements() для возвращаемого наблюдаемого, но он также игнорирует первый элемент, который я возвращаю, он только улавливает события, связанные с ошибкой, в цепочке. Если я выдам ошибку, а затем цепочку .ignoreElements, мой оператор catch позже сработает в цепочке. Возможно, я пытаюсь заставить rxjs делать то, чего он не должен делать.   -  person Sally    schedule 20.06.2017


Ответы (1)


Это ответ, который я придумал на данный момент.

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 в эпике, к сожалению, должны отправлять возвращаемый атрибут действия. Не в восторге, но на данный момент я остановился на этом.

person Sally    schedule 26.06.2017