0

我做了一个包装,用于通过身份验证头访问'rxjs/observable/dom/ajax'函数。那部分还行。我该如何使用rxjs尽早逃脱一个catch链?

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能够处理自己的身份验证问题,因此我可以将它用作使用相同身份验证的多个应用程序的导入。

+0

我不得不做几次 - 根据concatMap里面的结果取消所有concatMap的等待请求。我最近回答了一个类似的问题:https://stackoverflow.com/questions/44496395/rxjs-chain-observables-completing-at-any-point/44505681#44505681 –

+0

压缩不适合我,因为我必须完成任何从authjax返回之前返回它,所以我不能将以下链接的方法添加到zip。 我在返回的observable上尝试过.ignoreElements(),但它也忽略了我返回的第一个元素,它只拾取链中的错误相关事件。如果我抛出一个错误,然后链接.ignoreElements,我的catch语句将在链中触发。 我可能会试图让rxjs做一些它不应该做的事情。 – Sally

回答

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属性。不开玩笑,但这是我现在结束了。