[英]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.