web-dev-qa-db-fra.com

Angular 4 - Erreur de requête HTTP: vous avez indiqué 'non défini' lorsqu'un flux était attendu

En essayant de faire une requête HTTP Post, je reçois le message d'erreur suivant:

auth.service.ts? c694: 156 Une erreur s'est produite lors de la demande d'un nouveau fichier mot de passe, message d'erreur: vous avez indiqué 'non défini' où se trouvait un flux attendu. Vous pouvez fournir un élément Observable, Promise, Array ou Iterable.

La requête Http est précédée par une autre, qui fonctionne parfaitement.

Mon composant appelant le service:

requestNewPassword(formInput: NgForm) {
     if(formInput.controls['email'].value != '')
      this.authService.getApplicationAccessToken()
      .mergeMap((response: IAuthAppResponse) => this.authService.requestNewPassword(formInput, response.access_token))
      .subscribe(response => {
        // Content removed for simplicity
      })
    }

La méthode de service générant l'erreur:

public requestNewPassword(formData: NgForm, applicationAccessToken: string): Observable<any> {
      let headers = new HttpHeaders({
        'Authorization':'Bearer ' + applicationAccessToken
      });
      let email: string = formData.controls['email'].value;
      const body = {
        email: email
      };

      console.log('requestNewPassword call header: ' + headers.get('Authorization'));
      console.log('Email: ' + body.email);

      return this.http.post(this.baseUrl + '/api/user/password/forgot', body, {headers}).do(response => {
        console.log("New password was successfully sent to the e-mail adress");
      }).catch((error: HttpErrorResponse) => {
        console.log('Something went wrong requesting a new password, error message: ' + error.message);
        return Observable.throw(error);
      })
    }

Chaque fois que je saisis un e-mail dans le formulaire et que je le soumets, ce qui déclenche à son tour la méthode requestNewPassword du composant, le service mentionne l'erreur mentionnée plus haut.

L'en-tête et l'email sont correctement enregistrés, donc je ne pense pas qu'il y ait quoi que ce soit avec les données que je fournis.

N'ayant aucune idée de comment déboguer ceci, j'ai pensé que c'était une bonne idée de poster cela comme une question sur cette incroyable plate-forme.

Merci d'avance!

Mettre à jour

J'ai minimisé le code dans mon composant pour limiter le problème en ne chaînant pas les deux requêtes HTTP, mais en appelant uniquement la seconde, ce qui pose problème.

requestNewPassword(formInput: NgForm) {
      if(formInput.controls['email'].value != '')
      this.authService.requestNewPassword(formInput, "")
       .subscribe(response => {
         // Content removed for simplicity
       })
     }

J'ai maintenant une trace de pile complète:

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at Object.subscribeToResult (subscribeToResult.js?c011:74)
    at MergeMapSubscriber._innerSub (mergeMap.js?e2a2:132)
    at MergeMapSubscriber._tryNext (mergeMap.js?e2a2:129)
    at MergeMapSubscriber._next (mergeMap.js?e2a2:112)
    at MergeMapSubscriber.Subscriber.next (Subscriber.js?215e:89)
    at ScalarObservable._subscribe (ScalarObservable.js?d097:49)
    at ScalarObservable.Observable._trySubscribe (Observable.js?4e06:172)
    at ScalarObservable.Observable.subscribe (Observable.js?4e06:160)
    at MergeMapOperator.call (mergeMap.js?e2a2:87)
    at Observable.subscribe (Observable.js?4e06:157)
    at FilterOperator.call (filter.js?35ab:60)
    at Observable.subscribe (Observable.js?4e06:157)
    at MapOperator.call (map.js?c4af:56)
    at Observable.subscribe (Observable.js?4e06:157)
    at DoOperator.call (tap.js?7fa8:63)
    at Observable.subscribe (Observable.js?4e06:157)
    at CatchOperator.call (catchError.js?0867:79)
    at Observable.subscribe (Observable.js?4e06:157)
    at PasswordResetComponent.requestNewPassword (passwordReset.component.ts?c169:43)
    at Object.eval [as handleEvent] (PasswordResetComponent.html:7)
    at handleEvent (core.js?223c:13255)
    at callWithDebugContext (core.js?223c:14740)
    at Object.debugHandleEvent [as handleEvent] (core.js?223c:14327)
    at dispatchEvent (core.js?223c:9704)
    at eval (core.js?223c:12028)
    at SafeSubscriber.schedulerFn [as _next] (core.js?223c:4235)
    at SafeSubscriber.__tryOrUnsub (Subscriber.js?215e:238)
    at SafeSubscriber.next (Subscriber.js?215e:185)
    at Subscriber._next (Subscriber.js?215e:125)
    at Subscriber.next (Subscriber.js?215e:89)
    at EventEmitter.Subject.next (Subject.js?c1c6:55)
    at EventEmitter.emit (core.js?223c:4203)
    at NgForm.onSubmit (forms.js?ad57:5710)
    at Object.eval [as handleEvent] (PasswordResetComponent.html:7)
    at handleEvent (core.js?223c:13255)
    at callWithDebugContext (core.js?223c:14740)
    at Object.debugHandleEvent [as handleEvent] (core.js?223c:14327)
    at dispatchEvent (core.js?223c:9704)
    at eval (core.js?223c:10318)
    at HTMLFormElement.eval (platform-browser.js?023b:2614)
    at ZoneDelegate.invokeTask (zone.js?fad3:425)
    at Object.onInvokeTask (core.js?223c:4620)
    at ZoneDelegate.invokeTask (zone.js?fad3:424)
    at Zone.runTask (zone.js?fad3:192)
    at ZoneTask.invokeTask [as invoke] (zone.js?fad3:499)
    at invokeTask (zone.js?fad3:1540)
    at HTMLFormElement.globalZoneAwareCallback (zone.js?fad3:1566)

Etant donné que cela mentionne le code HTML, je vais également fournir le code HTML:

<form class="custom_form" #requestNewPasswordForm="ngForm" (ngSubmit)="requestNewPassword(requestNewPasswordForm)">
    <label>E-mail</label>
    <input class="custom_input" type="email" class="inputfield form-control" ngModel name="email">
    <button class="btn btn-default" type="submit">
      Send
    </button>
</form>
6
DennisN

Après beaucoup d’efforts, j’ai réussi à localiser et à résoudre le problème . Le problème était que j’ai un intercepteur d’autorisation qui intercepte chaque demande d’ajout d’un en-tête d’autorisation avec un jeton d’accès utilisateur.

Puisque l'appel que j'essayais de faire n'exigeait pas de jeton d'accès utilisateur, mais un jeton d'accès à l'application (authentifiez-vous en tant qu'application pour les requêtes HTTP publiques telles que register, mot de passe oublié, etc.), j'ai décidé de chaîner l'appel pour obtenir l'accès à l'application jeton et l'appel du mot de passe oublié et transmettez simplement le jeton d'accès à l'application récupérée à la méthode de mot de passe oublié de mon service et définissez-le dans l'en-tête Authorization. Ce code était tout bon. Le problème était que j'avais édité l'intercepteur pour vérifier s'il y avait un en-tête d'autorisation et si rien ne se passait et CE était la cause du bogue. 

Au lieu de ne rien faire, j'aurais dû simplement renvoyer la demande. Elle est donc exécutée sans modification de l'en-tête.

alors au lieu de

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if(request.headers.get('Authorization') == null) {
          //Code to add Authorization header
          return next.handle(requestWithAuthHeader)
        }
}

Je devais faire ce qui suit:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if(request.headers.get('Authorization') == null) {
          //Code to add Authorization header
          return next.handle(requestWithAuthHeader)
        } else {
          return next.handle(request);
        }
}

Sinon, la demande est interceptée et ne s'exécute jamais car elle n'est pas renvoyée par l'intercepteur. La méthode dans mon composant est abonnée au résultat de la méthode service et attend donc un observable, mais rien n'est jamais renvoyé car la demande a été interceptée et l'intercepteur a remarqué qu'un en-tête Authorization était déjà présent (défini dans le service). alors décidé de ne rien faire avec la demande.

Cela explique pourquoi j'ai eu l'erreur de dire que j'avais fourni non défini alors qu'un flux (observable) était attendu sur la ligne subscribe dans la méthode de mon composant.

14
DennisN

J'ai eu un problème très similaire. Cela a également fini par être un problème avec un intercepteur HTTP. Une fonction de désérialisation automatique s'exécutait sur toutes les réponses avec un modèle de point de terminaison API particulier. Les réponses qui n'étaient pas des exemples de HTTPResponse finirent par être mangées. L'ajout d'une instruction else renvoyant la réponse sans modification alors qu'il ne s'agit pas d'une instance de HTTPResponse résout le problème pour moi:

@Injectable()
export class DeserializerInterceptor implements HttpInterceptor {
  public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).map(
      event => {
        if (event instanceof HttpResponse) {
          let response = event as HttpResponse<any>;
          // ... deserialization of response object
          return response;
        } else {
          return event; // ... adding this else statement fixed the `undefined` error.
        }
      }
    );
  }
}

(Code de traitement des erreurs supprimé, pour plus de clarté.)

0
André C. Andersen