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

时间:2017-12-18 13:08:30

标签: angular http typescript rxjs

在尝试执行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请求但仅调用第二个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>

2 个答案:

答案 0 :(得分:16)

经过很多努力,我找到了解决问题的方法。 问题是我有一个授权拦截器拦截每个请求添加一个带有用户访问令牌的Authorization头。

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

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

所以而不是

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

否则请求被拦截并且永远不会执行,因为它不会被拦截器返回。 我的组件中的方法订阅了服务方法的结果,因此期望一个observable,但是没有任何东西被返回,因为请求被拦截并且拦截器注意到Authorization头已经存在(在服务中设置)所以决定对请求不做任何事。

这解释了为什么我收到错误声明我提供了undefined,而在我的组件方法的订阅行上预期了一个流(observable)。

答案 1 :(得分:0)

我有一个非常相似的问题。最终也成为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.
        }
      }
    );
  }
}

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