web-dev-qa-db-fra.com

Angular 2 - Gestion de plusieurs abonnements sur un seul observable

Je travaille sur une application Angular 2 et j'ai besoin de conseils pour gérer correctement les erreurs d'authentification.

Mon objectif final est de pouvoir gérer de manière centralisée les erreurs d'authentification (en particulier 401 et 403) pour chaque requête Http.

J'ai trouvé this question super utile pour me lancer, mais je suis bloqué quant à la bonne façon d'enregistrer mon gestionnaire d'erreurs pour chaque observable renvoyé par mon implémentation personnalisée de Http.

Voici un échantillon de ce avec quoi je travaille actuellement:

import { Injectable } from 'angular2/core';
import { Http, ConnectionBackend, Request, RequestOptions, RequestOptionsArgs, Response } from 'angular2/http';

import { Observable } from 'rxjs/Observable';


@Injectable()
export class ClauthHttp extends Http {

    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
        super(backend, defaultOptions);
    }

    get(url: string, options ? : RequestOptionsArgs): Observable < Response > {
        var response = super.get(url, options);

        return this._handleSecurityResponse(response);
    }

    /*
    Other overrides omitted for brevity...
    */

    private _handleSecurityResponse(response: Observable < Response > ): Observable < Response > {
        response.subscribe(null, (error: Response) => {
            // Do some nifty error handling here.
        });

        return response;
    }
}

La solution ci-dessus "fonctionne" avec un seul accroc ... Chaque demande HTTP est effectuée deux fois. Ce n'est pas bon.

Des conseils sur la façon de procéder correctement?

(Mettre à jour) Code de travail

Sur la base des informations contenues dans la réponse acceptée, voici à quoi ressemble la classe sous sa forme qui fonctionne correctement.

import {Injectable} from 'angular2/core';
import {Http, ConnectionBackend, Request, RequestOptions, RequestOptionsArgs, Response} from 'angular2/http';

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';


@Injectable()
export class ClauthHttp extends Http {

    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
        super(backend, defaultOptions);
    }

    get(url: string, options ? : RequestOptionsArgs): Observable < Response > {
        var response = super.get(url, options);

        return this._handleSecurityResponse(response);
    }

    /*
    Other overrides omitted for brevity...
    */

    private _handleSecurityResponse(response: Observable < Response > ): Observable < Response > {
        var sharable = response.share();

        sharable.subscribe(null, (error: Response) => {
            // Do some nifty error handling here.
        });

        return sharable;
    }
}
27
Tombatron

Cela est probablement dû au fait que votre Observable<Response> est un observable à froid, c'est-à-dire qu'il est "redémarré" pour chaque nouvel abonné. Pour une explication des observables chauds et froids, jetez un œil à Observables chauds et froids: existe-t-il des opérateurs "chauds" et "froids"? . Donc, ici, vous vous abonnez probablement une fois pour le gestionnaire de résultats et une autre fois pour le gestionnaire d'erreurs.

Vous devriez pouvoir contourner l'effet secondaire des abonnements en "partageant" votre observable,

c'est-à-dire remplacer

var response = super.get(url, options);

Avec

var response = super.get(url, options).share();`
31
user3743222