我有一个带有“请求”方法的 HttpClient 类,负责向 API 发出请求并返回承诺,我从不同的服务调用此方法,在其中管理返回的承诺。
问题是,如果 HttpClient 收到会话过期错误,我会自动将用户从 HttpClient 重定向到登录页面,但由于始终从“request”方法返回承诺,因此调用 httpClient.request 的代码将继续执行并向用户显示小吃栏错误。
有没有办法确保一旦重定向到登录就不会执行任何其他操作? (请注意,由于它是 SPA(我使用 Vue 和 Nuxt.js),因此页面不会重新加载,因此代码执行不会中断。此外,如果我尝试使用 location.href 刷新整个页面,则会出现错误在页面刷新前一刻显示)
这个想法是不必管理每个服务中过期会话的被拒绝的承诺,因为我将在所有服务甚至调用服务的函数中重写相同的代码,因为许多服务也会返回一个承诺,所以我会必须一次又一次地兑现这些承诺。
我想必须有一些更好的方法来处理这个问题,但我不知道如何。
这是我当前的HttpClient请求方法实现(为了更好的理解进行了总结):
export default class HttpClient {
[...]
/**
* Sends a request to the API and returns a promise with the result or an error.
*
* @param requestOptions
* @return Promise
*/
public async request(params) {
[...]
// Send request
try {
const response: ApiResponse = await $fetch(fetchUrl.toString(), requestOptions);
if (this.hasError(response)) {
const errorMessage = this.getErrorMessage(response as ErrorApiResponse);
if (await this.checkSessionExpired(errorMessage)) return Promise.reject(new SessionExpiredError(errorMessage));
return Promise.reject(new ApiHandledError(errorMessage));
}
return Promise.resolve(this.getData(response as SuccessApiResponse));
} catch (error) {
return Promise.reject(error);
}
}
}
我知道有几个与停止承诺传播相关的问题,但它们都没有回答我的问题,因为大多数答案都建议拒绝对我不起作用的承诺,因为这会在我的应用程序中向用户显示错误信息栏.
只需将您的请求包装成承诺,不要解决它。
所有调用前分配的资源最终都会被释放,多测试几次,最终就会看到释放的情况。
class HttpClient {
request(params) {
return new Promise(async(resolve, reject) => {
try{
const response = await new Promise((resolve, reject) => {
if(Math.random() > .33) {
setTimeout(() => resolve(Math.random() > .5 ? {error:'session expired'} : {status: 'ok'}), 1000);
}else{
setTimeout(() => reject(new Error('Some api error has happenned')), 1000);
}
});
if(response.error === 'session expired'){
console.log('session expired, redirecting to login route');
return;
}
resolve(response);
}catch(e){
reject(e);
}
});
}
}
const http = new HttpClient;
const registry = new FinalizationRegistry(obj => {
console.log(obj, ' released');
});
let callId = 1;
async function test(){
try{
const obj = {test: 'memory leak '.repeat(10000000)};
console.log('memory:', Math.round(performance.memory.usedJSHeapSize/1024)+'Kb');
registry.register(obj, 'test object ' + callId++);
const response = await http.request();
console.log('data received:', response);
}catch(e){
console.log('request error:', e.message);
}
}
<button onclick="test()">test http request</button>
<div>it will give 3 random outcomes</div>