You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular SSOLogin方法报错:HttpClient GET请求期望流却获undefined

Angular SSO登录请求报错排查与解决

问题描述

开发带SSOLogin单点登录功能的Angular认证服务时,检测到查询参数后调用SSOLogin方法触发以下错误:

TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.
RxJS 57
ssoLogin login.page.ts:104
ngOnInit login.page.ts:136
Angular 18
RxJS 49

错误发生在自定义头的HTTP GET请求阶段,已确认传入SSOLogin的username、access_token、id_token、consented_on参数均不为空,怀疑问题与请求头或HTTP请求结构相关。

相关代码片段

login.page.ts

/** First lifecycle hook */
ngOnInit() { 
    const username: string = this.activatedRoute.snapshot.queryParamMap.get('username');
    const access_token: string = this.activatedRoute.snapshot.queryParamMap.get('access_token');
    const id_token: string = this.activatedRoute.snapshot.queryParamMap.get('id_token');
    if (username && access_token && id_token) {
        this.ssoLogin(username, access_token, id_token, Math.floor(Date.now() / 1000).toString());
    }
 }

/** Method for logging in user retrieving query parameters (SSO Login) */
ssoLogin(username: string, access_token: string, id_token: string, consented_on: string) {
    this.authenticationSvc.SSOLogin(username, access_token, id_token, consented_on).subscribe({
      next: (res: Response) => {
        if (res.success && res.rows && res.rows.includes('extra')) {
          if (res.rows['extra'] === 'USER_EXISTS') {
            this.clearLocalStorage();
            this.requestLoginToken(this.authenticationSvc.consentedOn);
          } else if (res.rows['extra'] === 'USER_NOT_FOUND') {
            this.navUserNotFound();
          } else if (res.rows['extra'] === 'REG_WAIT_APPROVAL') {
            this.toastService.showError('Component.Toast.account-pending-approval', 'warning');
          } else {
            this.toastService.showError('Component.Toast.something-went-wrong');
          }
        } else {
          this.toastService.showError('Component.Toast.something-went-wrong');
        }
      },
      error: (error: Error) => {
        console.log(error);
        this.toastService.showError('Component.Toast.something-went-wrong');
      }
    });
  }

authentication.service.ts

/**
 * SSO Login
 * @param username
 * @param access_token
 * @param id_token
 * @param consented_on
 * @returns Service response
 */
SSOLogin(username: string, access_token: any, id_token: string, consented_on: string) {

    let headers = { 
        username: username,
        authorization: `Bearer ${access_token}`,
        jwt_token: id_token,
        consented_on: consented_on,
        client_id: environment.client_id,
        client_secret: environment.client_secret,
        clientKey: environment.clientKey
    };

    return this.http.get<any>(environment.baseUrl + 'user/getExistence', { headers })
        .pipe(
            map(
                (res: Response) => {
                    if (res && res.success && res.extra === 'USER_EXISTS') {
                        this.username = username;
                        this.jwt = id_token;
                        this.token = access_token;
                        this.consentedOn = consented_on;
                    }
                    return res;
                }
            ), catchError(this.handleError));

}

private handleError(error: HttpErrorResponse) {
 console.log(error);
 if (error.error === 'invalid_grant') {
 return throwError(false);
 } else {
 return throwError(true);
 }
 }

问题原因及解决方案

1. 错误处理函数上下文丢失

catchError中直接传入this.handleError会导致函数内部this指向异常,且RxJS的throwError需要传入工厂函数(RxJS 6+),直接传值会导致返回非Observable类型,触发报错。

修复方案:

  • 用箭头函数包裹handleError调用,确保上下文正确:
    catchError((error) => this.handleError(error))
    
  • 同时修改handleError的throwError调用方式:
    private handleError(error: HttpErrorResponse) {
     console.log(error);
     if (error.error === 'invalid_grant') {
     return throwError(() => false);
     } else {
     return throwError(() => true);
     }
     }
    

2. 请求头格式不符合Angular要求

Angular的HttpClient虽然支持自动将普通对象转为HttpHeaders,但复杂场景下可能转换失败,导致请求异常。

修复方案:
手动创建HttpHeaders实例:

import { HttpHeaders } from '@angular/common/http';

// ...

let headers = new HttpHeaders({ 
    username: username,
    authorization: `Bearer ${access_token}`,
    jwt_token: id_token,
    consented_on: consented_on,
    client_id: environment.client_id,
    client_secret: environment.client_secret,
    clientKey: environment.clientKey
});

3. 响应类型不匹配

HttpClient.get<any>指定响应为any,但map操作中声明res: Response会导致类型冲突,可能引发处理逻辑异常。

修复方案:
统一响应类型,将map中的类型改为any,或定义对应接口:

map((res: any) => {
    if (res && res.success && res.extra === 'USER_EXISTS') {
        this.username = username;
        this.jwt = id_token;
        this.token = access_token;
        this.consentedOn = consented_on;
    }
    return res;
})

4. 环境变量未正确加载

检查environment.client_id、environment.client_secret、environment.clientKey是否存在有效值,若为undefined会导致请求头字段异常。

调试方案:
在HTTP请求前打印头信息确认:

console.log('Request Headers:', headers);

内容的提问来源于stack exchange,提问作者Bill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:50:16