我在Angular HTTP拦截器代码中使用错误捕获时遇到了一个奇怪的问题。
似乎我的“.then()”语句链中的代码以某种方式被无序地触发。
这是我的代码...
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS, HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError, Observable, retry, switchMap, throwError } from 'rxjs';
import { FirebaseService } from '../services/firebase.service';
import { getAuth } from 'firebase/auth';
@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {
//AW-Note: Adding this in here to try the appearance of "Persistent Login"
static accessToken = '';
static apiKey = 'API_KEY_HERE';
constructor(private firebaseService: FirebaseService, private http: HttpClient) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = localStorage.getItem('token');
function refreshToken(): Promise<string> {
// api call returns Promise<string>
const auth = getAuth();
const myUser = auth.currentUser;
return myUser!.getIdToken(true);
}
async function getNewToken(): Promise<string> {
const value = await refreshToken() // how to unwrap the value inside this promise
return value;
}
console.log('Flowing through HTTP Interceptor');
req = req.clone({
//If you comment out the below line you will no longer send Credentials with the request
withCredentials: true,
setHeaders: { Authorization: `Bearer ${token}` }
});
return next.handle(req).pipe(/*retry(10),*/ catchError((err: HttpErrorResponse) => {
console.log("ERROR FOUND! CHECKING TO SEE IF IT IS A 401 ERROR NEXT. Error: " + err);
if (err.status === 401 || err.status === 0) {
console.log("NEW TOKEN NEEDED - Yo we got that 401 error going on - let's try and refresh that thang");
//Refresh Token from Firebase
console.log("Old Token: " + JSON.stringify(token));
console.log("Attempting to refresh token now...");
getNewToken()
.then((newToken) => {
console.log('New Token: ' + JSON.stringify(newToken));
localStorage.setItem('token', newToken);
console.log('Updated Local Storage with new token');
})
.then(() => {
console.log("Here is where the request will refresh");
return next.handle(req.clone({
withCredentials: true,
setHeaders: {
Authorization: `Bearer ${localStorage.getItem('token')}`
}
}))
})
.catch((error) => {
console.log("Error in Getting new token... Error: " + JSON.stringify(error));
});
}
return throwError(() => err);
}))
}
}
export const httpInterceptorProviders = [
{ provide: HTTP_INTERCEPTORS, useClass: HttpRequestInterceptor, multi: true },
];
因此,一旦localStorage中的令牌过期,代码就成功地检测到错误,并且在第一个“pipe()”块中捕获了它。
它成功地从Firebase获得了一个新令牌,但是当它向下移动到最后的“then”语句以使用新令牌重试API调用时,似乎在控制台日志语句“正在尝试刷新令牌...”之后立即调用了API,而不是像我期望的那样“这里是请求将刷新的地方”。
这是控制台的输出,所以你可以看到我在说什么...
Flowing through HTTP Interceptor
http.interceptor.ts:35
ERROR FOUND! CHECKING TO SEE IF IT IS A 401 ERROR NEXT. Error: [object Object]
http.interceptor.ts:44
NEW TOKEN NEEDED - Yo we got that 401 error going on - let's try and refresh that thang
http.interceptor.ts:46
Old Token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImU3OTMwMjdkYWI0YzcwNmQ2ODg0NGI4MDk2ZTBlYzQzMjYyMjIwMDAiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vdHV0b3JpYWwtYXBwLTEtODEyNDkiLCJhdWQiOiJ0dXRvcmlhbC1hcHAtMS04MTI0OSIsImF1dGhfdGltZSI6MTY4MjY4NTk3NCwidXNlcl9pZCI6ImUwUXdEYmZhVlpSdWZkaGF6S1FjdDU5ajdQVTIiLCJzdWIiOiJlMFF3RGJmYVZaUnVmZGhhektRY3Q1OWo3UFUyIiwiaWF0IjoxNjgyNzkwNjk4LCJleHAiOjE2ODI3OTQyOTgsImVtYWlsIjoiYWxleHdyaWdodDkyM0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiYWxleHdyaWdodDkyM0BnbWFpbC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ.eaPLxmi-wtsDV941M7A0ouMJhraDhKVbd_EFmdnFH3HZSCHRK4K4HRFZZ6RrvRo0FOd60NZLstE-MXzXumb7N6J6LOWqE_pUrtsylqDE15Wp4hJmcHP8HZmJA4wve3JlLox_i3bNgzY7F4NTuGsij92nZd1qa-uDd6_SI4o2ABtZGGfX-11RAUKN7sjGRTy_zMM2ielb8im7W8q8KbdW1OxISqJDE4rbqyBlLBbUZWI9z1RMRpxD_s6k6y3bZfYTq_seFWaKLH3rEMfMGujS4x_ytlHqWaLbU7v3BXRxhZJsgui3r1ktQROFZdJwApybQ8-tpeEZwp0KDdnx2cautA"
http.interceptor.ts:51
Attempting to refresh token now...
HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: 'Unknown Error', url: 'http://localhost:8080/api/tutorials', ok: false, …}
add-tutorial.component.ts:59
New Token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImU3OTMwMjdkYWI0YzcwNmQ2ODg0NGI4MDk2ZTBlYzQzMjYyMjIwMDAiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vdHV0b3JpYWwtYXBwLTEtODEyNDkiLCJhdWQiOiJ0dXRvcmlhbC1hcHAtMS04MTI0OSIsImF1dGhfdGltZSI6MTY4MjY4NTk3NCwidXNlcl9pZCI6ImUwUXdEYmZhVlpSdWZkaGF6S1FjdDU5ajdQVTIiLCJzdWIiOiJlMFF3RGJmYVZaUnVmZGhhektRY3Q1OWo3UFUyIiwiaWF0IjoxNjgyODc3MjIwLCJleHAiOjE2ODI4ODA4MjAsImVtYWlsIjoiYWxleHdyaWdodDkyM0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiYWxleHdyaWdodDkyM0BnbWFpbC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ.OoykyUgJdb6ugVaiJClcQjV6DpKQAQCl2Jx1VwHSrS77NzN5F0bfRCTHAS-wvXYgbzhAGw39fwq67HXoC74OdugKbJpnhpyf3e-TWLdN1SD195aBedPvB6KtApD7nj4WPTlYuE8mupcqXB2mw8NvDuxyZLV4pOv4A7ou5J7mJkrwiGU0WboM5HPz7LeoXP5QlxpPZ8dQ4f2cnJ3AKD9SFSgrojhi1tgrOh80YCsq5ZP46VXPj4ym-MchQ4T4rQh6wjZ9NllzngM0-QvZD4Bz9m52g5hBaICqVQnVpbzX_xMnixZYI7N9LGC3F-GXEeLF-IhLgdEbcM8vL7LypOZyPQ"
http.interceptor.ts:59
Updated Local Storage with new token
http.interceptor.ts:61
About to retry the API Call now
http.interceptor.ts:65
Here is where the request will refresh
这里的任何帮助都将不胜感激。我的.then()语句有问题吗?对 typescript 、角化和像这样的promise处理来说相当陌生。谢谢。
我已经尝试过在.then()语句周围使用一些语句,但是我认为return语句看起来似乎执行得 * 早 *
(the HTTP请求在日志显示“HttpErrorResponse”的位置发出)
提前感谢!
1条答案
按热度按时间wsxa1bj11#
这是最终为我工作的解决方案。
主要的两个变化是:
1.使用from(refreshToken())将refreshToken()返回的promise转换为一个observable,该observable可以通过管道传输到新的switchMap操作符中。
1.将重试逻辑移动到switchMap操作符中,以便它仅在获得新令牌并将其添加到本地存储后重试API调用。