0

J'ai fait un wrapper pour accéder aux fonctions 'rxjs/observable/dom/ajax' avec un en-tête d'authentification. Cette partie s'est bien passée.Comment puis-je échapper à une chaîne de capture tôt avec rxjs?

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()}) 
}; 

Donc, cela s'utilise à la place d'ajax. Voici un exemple de l'utilisation dans une épopée.

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}) 
    ); 
    }); 

Maintenant, je suis dans la première étape d'essayer de faire une passe de test simple en utilisant seulement la méthode authjax.get. Je veux que 401 réponses du serveur soient interceptées par authjax, et qu'authjax renvoie une action de déconnexion, et annule toutes les méthodes chaînées suivantes. Ceci est ma dernière tentative pour authjax.get. Il fonctionne pour les réponses ajax réussies, et pour les réponses non 401 ajax. Il ne retourne rien, même l'action de fermeture de session, quand il frappe le 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()}) 
}; 

Je lis rxjs docs, mais trouver qu'il ya une hypothèse que vous jamais besoin de passer sur ou annuler une diffuser dans un flux. Je sais qu'il y a peut-être des options où je pourrais gérer plus dans Epic lui-même, mais je veux qu'authjax puisse prendre soin de ses propres soucis d'authentification ainsi je peux l'employer comme une importation à travers plusieurs applications utilisant la même autorisation.

+0

J'ai dû faire la même chose deux fois - annuler toutes les demandes en attente de concatMap en fonction du résultat à l'intérieur de concatMap. J'ai récemment répondu à une question similaire: https://stackoverflow.com/questions/44496395/rxjs-chain-observables-completing-at-any-point/44505681#44505681 –

+0

zip n'a pas fonctionné pour moi parce que je dois remplir tout est renvoyé par authjax avant de le renvoyer, donc je ne peux pas ajouter les méthodes chaînées suivantes dans un zip. J'ai essayé .ignoreElements() sur un observable retourné mais il ignore aussi le premier élément que je retourne, il ne prend en compte que les événements liés à l'erreur dans la chaîne. Si je lance une erreur et enchaîne ensuite sur .ignoreElements, ma déclaration de catch plus tard dans la chaîne se déclenche. J'essaie peut-être de faire en sorte que rxjs fasse quelque chose qu'elle n'est pas censée faire. – Sally

Répondre

0

C'est la réponse que j'ai trouvée pour le moment.

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; 
    }); 
}; 

Il arrête toutes les méthodes de chaîne si l'état est un 401 et renvoie toutes les instructions catch suivantes. Les déclarations catch dans l'épopée doivent malheureusement envoyer l'attribut d'action renvoyé. Pas attisé mais c'est comme ça que j'ai fini par passer à autre chose pour le moment.