簡體   English   中英

Angular HTTP Interceptor 執行兩次內部 http 請求

[英]Angular HTTP Interceptor executing inner http request twice

我的應用程序使用JWT Token向后端進行身份驗證。 我有一個角度Interceptor ,可以捕獲 http 調用中的任何錯誤。 此攔截器檢查調用是否返回401 Unauthorized響應,如果是,則調用端點以刷新令牌,然后再次重試原始調用。

我的問題是由於某種原因,對 refreshToken 端點的調用進行了兩次。

這是我的攔截器(為簡潔起見進行了編輯):

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError((error: any) => {
        switch (error.status) {
          // unauthorized
          case 401:
            // the token is stored in an NGRX store, so retrieve it first
            return this.userStore.pipe(select(fromUser.getUserAccessToken)).pipe(
              take(1),
              mergeMap(userToken => {
                if (userToken) {
                  // token exists but may be invalid, try to refresh
                  return this.userService.refreshToken(userToken).pipe(
                    switchMap(refreshedToken => {
                      if (refreshedToken) {
                        ...
                      } else {
                        // token was not refreshed, delete session
                        ...
                      }
                    })
                  );
                }
              })
            );
        }
      })
    );
  }

return this.userService.refreshToken(userToken)是被執行兩次的語句(使用相同的原始令牌),所以第一次調用 refresh 將通過,第二次調用顯然會失敗,因為它試圖刷新相同的令牌再次,導致用戶會話被刪除。

任何想法為什么?

更新:我仍在挖掘這個。 我在代碼中放置了一堆斷點和console.log

      catchError((error: any) => {
        >>>>> console.log('1');
        switch (error.status) {
          case 401:
            return this.userStore.pipe(select(fromUser.getUserAccessToken)).pipe(
              take(1),
              mergeMap(userToken => {
                >>>>> console.log('2');
                if (userToken) {
                  return this.userService.refreshToken(userToken).pipe(
                    switchMap(refreshedToken => {
                      >>>>> console.log('3');

Console.log #1 和 #2 只打印到控制台一次,這意味着http error只被捕獲一次。 但是 #3 被打印了兩次,我認為這意味着對刷新端點的調用被進行了兩次,或者 observable 以某種方式返回了兩個值?

不知道為什么,但似乎refreshToken輸出多個值。 這可以由take操作員輕松解決。 像這樣的東西:

 return this.userService.refreshToken(userToken).pipe(
                take(1),
                switchMap(refreshedToken => {
                  >>>>> console.log('3');

您的后端調用可能是一個 OPTIONS 請求

預檢請求

與簡單請求(上面討論過)不同,“預檢”請求首先向其他域上的資源發送 HTTP OPTIONS 請求標頭,以確定實際請求是否可以安全發送。 跨站點請求是這樣預檢的,因為它們可能會對用戶數據產生影響。 特別是,在以下情況下對請求進行預檢:

它使用 GET 或 POST 以外的方法。 此外,如果 POST 用於發送內容類型不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 的請求數據,例如,如果 POST 請求向服務器發送 XML 負載使用 application/xml 或 text/xml,然后預檢請求。 它在請求中設置自定義標頭(例如,請求使用 X-PINGOTHER 等標頭)

首先,您確實需要提供一個 StackBlitz 或類似的錯誤信息,以便我們幫助診斷。 盡管如此,我對此很好奇,因為我以前遇到過這樣的問題,所以我做了一些研究。 我發現的大多數示例都表明, refreshToken方法返回的 Observable 是共享的,以防止多個訂閱。 在這個答案https://stackoverflow.com/a/52720791/5799931 中,您可以看到this.authService.refreshToken() Observable 是共享的。 我會試試這個

return this.userService.refreshToken(userToken).pipe(
       share(), <----- ADD THE SHARE HERE
       switchMap(refreshedToken => {
          if (refreshedToken) {
             ...
          } else {
            // token was not refreshed, delete session
            ...
          }
       })
   );

您還可以在refreshToken方法中共享 HttpClient 返回的 Observable。

暫無
暫無

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

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