簡體   English   中英

Angular 您在預期 stream 的地方提供了“未定義”

[英]Angular You provided 'undefined' where a stream was expected

請幫忙。 當從攔截器調用 refreshAccessToken 時會發生此錯誤。但代碼執行仍在繼續。

錯誤類型錯誤:您在預期 stream 的位置提供了“未定義”。 您可以提供 Observable、Promise、ReadableStream、Array、AsyncIterable 或 Iterable。

這是 http 攔截器,它在時間過去時調用刷新令牌。

import {Injectable} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs';
import {AuthService} from "../../../services/auth.service";
import {SharedService} from "../../../services/shared.service";
import * as moment from "moment";

@Injectable()
export class HttpInterceptorInterceptor implements HttpInterceptor {

  constructor(private sharedService: SharedService, private authService: AuthService) {
  }

  putTokenInRequest(request: HttpRequest<any>, access_token: any): HttpRequest<any> {
    return request = request.clone({
      setHeaders: {
        Authorization: `Bearer ${access_token}`
      }
    })
  }

  excludeRequest(request: HttpRequest<any>): boolean {
    let request_to_exclude = [
      "/protocol/openid-connect/token"
    ]
    let exclude = false
    for (let req of request_to_exclude) {
      if (request.url.toString().includes(req)) {
        exclude = true
      }
    }
    return exclude;
  }


  intercept(request: HttpRequest<any>, next: HttpHandler) :any{

    if (this.excludeRequest(request) != true) {

        //before every request check if access token has expired
        let access_token_expire_date = localStorage.getItem("access_token_expire_date")

        //subtract 10 sc for safety
        if (moment().isAfter(moment(access_token_expire_date).subtract(10, 's'))) {
          console.log("access_token_expired")
          let refreshToken = localStorage.getItem("refresh_token")
          this.authService.refreshAccessToken(refreshToken).subscribe(response => {
            localStorage.setItem("refresh_token", response.refresh_token)
            localStorage.setItem("access_token", response.access_token)
            let access_token_expire_date = moment().add(response.expires_in, 's')
            let refresh_expire_date = moment().add(response.refresh_expires_in, 's')
            localStorage.setItem('access_token_expire_date', access_token_expire_date.toString())
            localStorage.setItem('refresh_expire_date', refresh_expire_date.toString())
            return next.handle(this.putTokenInRequest(request, response.access_token))
          })

        } else {
          //if access_token is active again.
          let access_token = localStorage.getItem('access_token')
          return next.handle(this.putTokenInRequest(request, access_token))
        }
    }
    else {
      //if request is excluded from interception just move on and don,t change it.
      return next.handle(request);
    }

  }
}

服務

import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders, HttpParams} from "@angular/common/http";
import {environment} from "../../environments/environment";
import {Observable} from "rxjs";

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  keyckloakUrl
  baseUrl
  constructor(private http: HttpClient) {
    this.keyckloakUrl = environment.keyckloakUrl;
    this.baseUrl = environment.baseUrl;
  }

  getExccessToken(code: any): Observable<any> {

    const params = new HttpParams({
      fromObject: {
        client_id: 'authorization_code_grant_type',
        grant_type: 'authorization_code',
        code: code,
        redirect_uri:'http://localhost:4200/dashboard/token_redirect'
      }
    });

    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/x-www-form-urlencoded',
      })
    };
    return this.http.post(`${this.keyckloakUrl}/realms/master/protocol/openid-connect/token`, params.toString(),httpOptions);
  }

  // logout():Observable<any>{
  //   return this.http.get(` http://localhost:8088/auth/realms/master/protocol/openid-connect/logout?redirect_uri=http://localhost:4200`);
  // }

refreshAccessToken(refreshToken:any):Observable<any>{
  // const params = new HttpParams({
  //   fromObject: {
  //     client_id: 'authorization_code_grant_type',
  //     grant_type: 'refresh_token',
  //     refresh_token: refreshToken,
  //   }
  // });
  // const httpOptions = {
  //   headers: new HttpHeaders({
  //     'Content-Type': 'application/x-www-form-urlencoded',
  //   })
  // };
  let body = new URLSearchParams();
  body.set('client_id', 'authorization_code_grant_type');
  body.set('grant_type', 'refresh_token');
  body.set('refresh_token', refreshToken);

  let options = {
    headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
  };
debugger
  return this.http.post<any>(`${this.keyckloakUrl}/realms/master/protocol/openid-connect/token`,  body.toString(),options);
}

  logout():Observable<any>{
    return this.http.post(`${this.baseUrl}/logout`,{})
}
}

根據Angular 官方文檔,這是一個正確的interceptor接口

interface HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
}

您正在將intercept的返回類型修改為any並丟失了所有types safety

intercept(request: HttpRequest<any>, next: HttpHandler) :any

如果您不這樣做,任何體面的代碼編輯器都會為您突出顯示問題。

如果你看看這個代碼塊:

        if (moment().isAfter(moment(access_token_expire_date).subtract(10, 's'))) {
          console.log("access_token_expired")
          let refreshToken = localStorage.getItem("refresh_token")
          this.authService.refreshAccessToken(refreshToken).subscribe(response => {
            localStorage.setItem("refresh_token", response.refresh_token)
            localStorage.setItem("access_token", response.access_token)
            let access_token_expire_date = moment().add(response.expires_in, 's')
            let refresh_expire_date = moment().add(response.refresh_expires_in, 's')
            localStorage.setItem('access_token_expire_date', access_token_expire_date.toString())
            localStorage.setItem('refresh_expire_date', refresh_expire_date.toString())
            return next.handle(this.putTokenInRequest(request, response.access_token))
          })

您沒有為intercept function 返回任何內容, return next.handle(this.putTokenInRequest(request, response.access_token))在您的subscribe回調中,因此您返回的內容基本上是voidundefined

所以你所要做的就是返回stream代替:

...
    let refreshToken = localStorage.getItem('refresh_token');
    return this.authService.refreshAccessToken(refreshToken).pipe(
      map((response) => {
        localStorage.setItem('refresh_token', response.refresh_token);
        localStorage.setItem('access_token', response.access_token);
        let access_token_expire_date = moment().add(response.expires_in, 's');
        let refresh_expire_date = moment().add(
          response.refresh_expires_in,
          's'
        );
        localStorage.setItem(
          'access_token_expire_date',
          access_token_expire_date.toString()
        );
        localStorage.setItem(
          'refresh_expire_date',
          refresh_expire_date.toString()
        );
        return next.handle(
          this.putTokenInRequest(request, response.access_token)
        );
      })
    );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM