rxjs retryWhen promise is resolved



我正在实现一个调用服务器获取数据的Angular服务。在每次调用中,我都需要传递一个持续大约一分钟的令牌,然后我需要映射响应以获得特定字段。因此,如果我的主调用失败,我需要再次调用令牌,等待响应,然后重试我的第一个调用,是否有一种简单的方法来做到这一点?以下是我的两种方法(它们都不能正常工作):

return this.http.post(url,
firstCallText(this.token), { 
responseType: 'text',
headers
})
.pipe(
map((xmlString: string) => {
let asJson = this.xmlStringToJson(xmlString);
return asJson["soap:Envelope"]["soap:Body"]["Response"]["#text"];
}),
catchError(async err=>{
await this.http.post(url,
getToken(),
{ 
responseType: 'text',
headers
}).pipe(map((xmlString: string) => {
let asJson = this.xmlStringToJson(xmlString);
this.token = asJson["soap:Envelope"]["soap:Body"]["Response"]["Token"]["#text"];
})).toPromise()
return EMPTY
}),
retry()
)

第一个方法失败,因为在接收到新令牌之前调用了retry()。我的第二种方法:

return this.http.post(url,
firstCallText(this.token), { 
responseType: 'text',
headers
})
.pipe(
map((xmlString: string) => {
let asJson = this.xmlStringToJson(xmlString);
return asJson["soap:Envelope"]["soap:Body"]["Response"]["#text"];
}),
retryWhen((errors) =>{
this.http.post(url,
getToken(),
{ 
responseType: 'text',
headers
}).pipe(map((xmlString: string) => {
let asJson = this.xmlStringToJson(xmlString);
this.token = asJson["soap:Envelope"]["soap:Body"]["Response"]["Token"]["#text"];
})).toPromise()
return EMPTY          
})
)

第二个不能正确重试,我不想设置延迟,因为令牌调用可能更短或更长。

您在这里面临的问题是retry模仿没有错误的源,您实际上想要处理错误本身。

所以我的建议是扩展你的catchError操作符,这样它就可以自己处理"失败"。Case并恢复操作,以便从服务器获取数据。

下面是一个伪代码解决方案

// Answer for rxjs retryWhen promise is resolved  :https://stackoverflow.com/questions/72061841/rxjs-retrywhen-promise-is-resolved
const {interval, of, catchError} = rxjs;
const { switchMap, tap } = rxjs.operators;
// Start of Mock for your backednd
// requestToBeValidatedWithToken will either return success meassage whenver the token is valid or throw an error when the token has expired
let token = 0;
const requestToBeValidatedWithToken = () => {
if (token < 0) {
throw 'Expired token';
}
return of('Validated request suceeds');
};
// this mocks the refresh token logic
const fetchNewToken = () => {
token = 3;
return of('This refreshes the token');
};
// Timer that will invalidate your token
interval(1000).subscribe(() => {
token--;
if (token < 0) {
console.log('BE message: Token has expired');
}
});
// End of Mock for your backednd
// Start of rxjs pseudo code
// This will mock your base request stream, imaginge as the request is made each seconds
const methodInYourService = () => {
const httpCall = interval(1000).pipe(
switchMap(() => {
return requestToBeValidatedWithToken();
}),
catchError((e) => {
// This checks makes sure that only the "Expired token" case is handled so that you dont end in infinite loop
if (e === 'Expired token') {
console.log('Fire refresh token request', e);
return fetchNewToken().pipe(
tap(() => console.log('save your token as you recieve it')),
switchMap(() => httpCall))
}
return e;
})
);
return httpCall;
};
// This is the code inside your component, e.g. the place where you subscribe for the data
methodInYourService().subscribe(
(x) => {
console.log(x, 'fin');
},
(e) => {
console.log('Will never come here, as we are handling the error');
}
);
<script src="https://unpkg.com/rxjs@^7/dist/bundles/rxjs.umd.min.js"></script>

你可以在这里找到有效的伪代码解决方案生活例子

相关内容

最新更新