Problème
Je suis abonné à un httpClient.get observable deux fois. Cependant, cela signifie que mon appel est exécuté deux fois. Pourquoi est-ce?
Preuve
Pour chaque subscribe () que je fais, je reçois une autre ligne dans la page de connexion.
Code (bouton de la page de connexion onSubmit ())
var httpHeaders = new HttpHeaders()
.append("Authorization", 'Basic ' + btoa(this.username + ':' + this.password));
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders});
observable.subscribe(
() => {
console.log('First request completed');
},
(error: HttpErrorResponse) => {
console.log('First request error');
}
);
observable.subscribe(
() => {
console.log('Second request completed');
},
(error: HttpErrorResponse) => {
console.log('Second request error');
}
);
Console
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:54 First request error
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:62 First request error
Contexte non pertinent
J'ai un objet LogonService qui gère toutes les fonctionnalités de connexion. Il contient une variable booléenne indiquant si je suis connecté ou non. Chaque fois que j'appelle la fonction de connexion, elle s'abonne à l'observable de httpClient.get pour définir la variable de connexion sur true ou sur false. Mais la fonction de connexion retourne également l'observable, auquel on s'abonne. Il m'a fallu du temps pour lier la double demande à la double souscription. S'il existe un meilleur moyen de suivre l'identifiant que via une variable, faites le moi savoir! J'essaie d'apprendre angulaire :)
Essayez d’utiliser l’opérateur share
sur le résultat de HttpClient.get
, comme ceci:
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders })
.pipe(share());
Vous devez ajouter l'importation suivante au-dessus de votre script:
import { share } from 'rxjs/operators';
L’opérateur share
crée une hot
observable, c’est-à-dire partagée entre les abonnés. Mais il y a bien plus que cela, je suggérerais cet article de plonger plus profondément (vous pouvez bien sûr aussi google up hot vs cold observables
pour trouver plus).
Votre observable est froid:
Un observable est froid si le producteur de ses notifications est créé chaque fois qu'un observateur souscrit à l'observable. Par exemple, un la minuterie observable est froide; chaque fois qu'un abonnement est fait, un nouveau la minuterie est créée.
Vous devez multicast
votre Observable, ou en d'autres termes, pour le rendre chaud:
Un observable est chaud si le producteur de ses notifications ne l’est pas créé chaque fois qu'un observateur s'abonne à l'observable. Pour Par exemple, une observable créée en utilisant fromEvent est hot; l'élément qui produit les événements existe dans le DOM - il n’est pas créé lorsque le fichier l'observateur est abonné.
Pour cela, vous pouvez utiliser share operator, mais il ne peut toujours pas vous garantir un seul appel http. Partager partagera multicast
votre observable, ce qui le partagera entre les abonnés, mais une fois l'appel http terminé, il effectuera un nouvel appel http pour les nouveaux abonnés.
Si vous souhaitez un comportement de mise en cache (effectuer l'appel une fois puis fournir la valeur à chaque abonné chaque fois qu'il s'abonne), vous devez utiliser publishReplay().refCount()
.
Outre les réponses ci-dessus, vous pouvez affecter à observable votre service http
, puis vous abonner aux données get. Par exemple:
export class App implements OnInit {
cars$: Observable<Car[]>;
constructor(private carsService: carsService) {
}
ngOnInit() {
this.lessons$ = this.lessonsService.loadLessons().publishLast().refCount();
this.lessons$.subscribe(
() => console.log('lessons loaded'),
console.error
);
}
}