Моя проблема заключается в следующем: мое веб-приложение использует токены аутентификации, срок действия которых может истечь. Когда срок их действия истекает, сервер отправляет ошибку 401, предлагая браузеру сначала выполнить запрос sh token refre. Я использую оператор retryWhen()
, чтобы справиться с этой ситуацией. Оператор retryWhen()
использует следующий код для запроса нового токена.
public tokenExpired = ({
maxRetryAttempts = 1
}: {
maxRetryAttempts?: number,
} = {}) => (attempts: Observable<any>) => {
return attempts.pipe(
mergeMap((error, i) => {
const retryAttempt = i + 1;
if((error && error.headers && (!error.headers.get("reason-unauthorized") || !(error.headers.get("reason-unauthorized") === "authentication-token-expires-soon"))) || retryAttempt > maxRetryAttempts) {
return throwError(error);
}
return this.requestNewToken().pipe(
concatMap(refreshStatus => {
if(refreshStatus === TokenRefreshStatus.TOKEN_REFRESHED)
return timer(0);
else if(refreshStatus === TokenRefreshStatus.TOKEN_REFRESH_FAILED)
return throwError(error);
else if(refreshStatus === TokenRefreshStatus.AWAIT_REFRESH && this.loggedIn.value){
let maxWaitTimeInMilliSeconds = 4000;
interval(100).pipe(takeWhile(() => !(this.tokenRefreshStatus !== TokenRefreshStatus.AWAIT_REFRESH || maxWaitTimeInMilliSeconds <=0)))
.subscribe(value => {maxWaitTimeInMilliSeconds -= 100;});
if(this.tokenRefreshStatus === TokenRefreshStatus.TOKEN_REFRESHED)
return timer(0);
else return throwError(error);
}
else
return throwError(error);
}));
})
);
}
Таким образом, оператор retryWhen будет иметь tokenExpired
в качестве лямбда retryWhen(tokenExpired())
. Поскольку несколько запросов могут запускаться почти одновременно, я сделал код таким образом, что только первый запрос будет запускать HTTP-запрос token refre sh через this.requestNewToken()
, а любой другой запрос, который делает аналогичный вызов через retryWhen
, будет получить сообщение AWAIT_REFRESH
от метода requestNewToken()
. Таким образом я предотвращаю многократные запросы на новый токен.
Когда получено AWAIT_REFRE SH, код должен каждые 100 миллисекунд проверять, изменилось ли tokenRefreshStatus
на TOKEN_REFRESHED
или TOKEN_REFRESH_FAILED
. Он может повторять это сейчас дольше, чем около 4000 миллисекунд. Следовательно, интервал также должен перестать повторяться, когда maxWaitTimeInMilliSeconds
достигнет 0 или ниже. После этого есть оператор if, который проверяет, равно ли TokenRefreshStatus
TOKEN_REFRESHED
, если он это делает, он отправляет обратно timer(0)
, если нет, он выдает исходную ошибку, полученную оператором retryWhen
.
Моя проблема в том, что приложение не ждет, пока код интервала завершится sh. Он просто переходит прямо к оператору if под этим, заставляя его всегда выдавать ошибку. Я думаю, мне не следует подписываться на интервал, но вместо этого я должен вернуть его как новую наблюдаемую, которая выполняет итерацию интервала И проверку после этого, чтобы увидеть, обновился ли токен после завершения интервала. Я просто не знаю, как мне это сделать.
Может ли кто-нибудь указать мне правильное направление? Спасибо