Angular 4 - Http 请求错误:您在预期流的位置提供了“未定义”

Posted

技术标签:

【中文标题】Angular 4 - Http 请求错误:您在预期流的位置提供了“未定义”【英文标题】:Angular 4 - Http request error: You provided 'undefined' where a stream was expected 【发布时间】:2018-05-31 20:08:27 【问题描述】:

在尝试执行 HTTP Post 请求时,我收到以下错误:

auth.service.ts?c694:156 出现问题,请求新的 密码,错误消息:您提供了流所在的“未定义” 预期的。您可以提供 Observable、Promise、Array 或 Iterable。

Http 请求之前有另一个,效果很好。

我的组件调用服务:

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
      )
    

抛出错误的服务方法:

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

每当我在表单中输入电子邮件并提交时,这又会触发组件的 requestNewPassword 方法,我会从服务中收到上述错误。

标题和电子邮件记录正确,因此我认为我提供的数据没有任何内容。

由于我不知道如何调试它,我认为在这个令人难以置信的平台上发布这个问题是个好主意。

提前致谢!

更新

我通过不链接两个 HTTP 请求而只调用第二个请求来最小化组件中的代码以缩小问题范围,这会造成麻烦。

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

我现在得到了完整的堆栈跟踪:

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)

由于这里提到了html,我将提供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>

【问题讨论】:

在询问错误时,请始终发布错误的准确和完整的堆栈跟踪。它告诉问题出在哪里 我更新了问题 HttpErrorResponse 的状态如何?这似乎是来自您的服务器的错误消息。 每当我尝试记录状态时,它只会返回 undefined 我不认为这是服务器错误,因为它适用于邮递员。 【参考方案1】:

我有一个非常相似的问题。它也最终成为 HTTP 拦截器的问题。我在具有特定 API 端点模式的所有响应上运行了一个自动反序列化功能。不是HTTPResponse 实例的响应最终被吃掉了。添加一个 else 语句,当不是 HTTPResponse 的实例时返回未触及的响应为我解决了这个问题:

@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.
        
      
    );
  

(为了清楚起见,删除了错误处理代码。)

【讨论】:

【参考方案2】:

经过大量的努力,我已经设法找到并解决了问题。 问题是我有一个授权拦截器,它拦截每个请求以添加带有用户访问令牌的授权标头。

由于我尝试执行的调用不需要用户访问令牌,而是应用程序访问令牌(作为公共 Http 请求(如注册、忘记密码等)的应用程序进行身份验证),我决定将调用链接到 get应用程序访问令牌和对忘记密码的调用,只需将检索到的应用程序访问令牌传递给我的服务中的忘记密码方法,并将其设置在授权标头中。这段代码一切都很好。问题是我已经编辑了拦截器以检查是否存在授权标头,如果是,则什么也不做,这就是导致错误的原因。

我应该只返回请求,而不是什么都不做,所以它会在不修改标头的情况下执行。

所以而不是

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

我必须做到以下几点:

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

否则请求会被拦截并且永远不会执行,因为它不会被拦截器返回。 我的组件中的方法订阅了服务方法的结果,因此需要一个可观察的,但由于请求被拦截并且拦截器注意到授权标头已经存在(在服务中设置)所以决定没有返回任何内容对请求不执行任何操作。

这解释了为什么我收到错误消息,指出我提供了 undefined 而我的组件方法中的订阅行上需要一个流(可观察的)。

【讨论】:

谢谢,我遇到了与您类似的问题,您的解决方案奏效了。

以上是关于Angular 4 - Http 请求错误:您在预期流的位置提供了“未定义”的主要内容,如果未能解决你的问题,请参考以下文章

令牌刷新后Angular 4拦截器重试请求

在预请求脚本中从集合中调用请求

(SystemJS) XHR 错误@angular/commobundles/common.umd.js/http 未找到

Angular 4.3 - HTTP 拦截器 - 刷新 JWT 令牌

Angular 11 您在预期流的位置提供了“未定义”

我的 Angular 4 应用程序无法向 Spring Boot Server 请求令牌