获取和获取重试的拦截器? (Javascript)
Interceptor for fetch and fetch retry? (Javascript)
我正在尝试为 javascript 中的获取创建一个拦截器(反应更具体)。它应该从每次调用的提取中获取结果,如果是 401 错误,它应该启动对另一个路由的新提取调用以获取 cookie(刷新令牌)。然后,应该再次尝试原始的提取调用(因为现在用户已登录)。
我已经设法触发了新的获取调用并为每个调用发回了 cookie,但是我遇到了以下两个问题:
我现在不知道如何在收到刷新令牌后重试提取调用。那可能吗?我找到了 fetch-retry npm (https://www.npmjs.com/package/fetch-retry),但不确定在应该为原始 fetch 调用完成时如何以及是否可以在拦截器上实现它。
我似乎对 async await 做错了什么(我认为),因为拦截在 returning 数据(原始状态码)之前不等待 fetch 调用fetch 似乎是 401 而不是 200,我们得到 cookie 后应该是 200。我还尝试 return 拦截器内部 fetch 的响应,但是 returned 未定义)。
知道如何解决这个问题吗?有人做过类似的事情吗?
下面是我的代码:
(function () {
const originalFetch = fetch;
fetch = function() {
return originalFetch.apply(this, arguments).then(function(data) {
if(data.status === 401) {
console.log('not authorized, trying to get refresh cookie..')
const fetchIt = async () => {
let response = await fetch(`/api/token`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
});
}
fetchIt();
}
return data
});
};
})();
编辑:为了更清楚地说明我所追求的。我需要一个像我上面描述的拦截器来工作,这样我就不必在每次 fetch 调用后都做这样的事情:
getData() {
const getDataAsync = async () => {
let response = await fetch(`/api/loadData`, { method: 'POST' });
if(response.status === 401) {
let responseT = await fetch(`/api/token`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
});
if(responseT.status === 401) {
return responseT.status
}
if(responseT.status === 200) {
response = await fetch(`/api/loadData`, { method: 'POST' });
}
}
let data = await response.json();
//Do things with data
};
getDataAsync();
};
所以基本上拦截器应该:
- 检查是否有401,如果有则:
- 获取api/token
- 如果api/token returns 401,它应该return那个。
- 如果api/token returns 200, 应该运行 重新获取原始数据
尝试重新调整获取承诺,而不是等待它。
(function () {
const originalFetch = fetch;
fetch = function () {
return originalFetch.apply(this, arguments).then(function (data) {
if (data.status === 200) console.log("---------Status 200----------");
if (data.status === 404) {
console.log("==========404 Not Found.=============");
return fetch(`https://jsonplaceholder.typicode.com/todos/2`);
} else {
return data;
}
});
};
})();
function test(id) {
//will trigger 404 status
return fetch(`https://jsonplaceholder.typicode.com/todos/` + id, {
method: "POST",
credentials: "include",
});
}
test(1).then((i) => console.log(i));
您可以简单地使用 originalFetch
作为令牌并等待响应,如果响应是 401 那么您只需 return 清空对第一次获取调用的响应,否则您更新令牌然后让它进入下一个条件这将重新运行旧请求。
let TEMP_API = {
'401': {
url: 'https://run.mocky.io/v3/7a98985c-1e59-4bfb-87dd-117307b6196c',
args: {}
},
'200': {
url: 'https://jsonplaceholder.typicode.com/todos/2',
args: {}
},
'404': {
url: 'https://jsonplaceholder.typicode.com/todos/1',
args: {
method: "POST",
credentials: "include"
}
}
}
const originalFetch = fetch;
fetch = function() {
let self = this;
let args = arguments;
return originalFetch.apply(self, args).then(async function(data) {
if (data.status === 200) console.log("---------Status 200----------");
if (data.status === 401) {
// request for token with original fetch if status is 401
console.log('failed');
let response = await originalFetch(TEMP_API['200'].url, TEMP_API['200'].args);
// if status is 401 from token api return empty response to close recursion
console.log("==========401 UnAuthorize.=============");
console.log(response);
if (response.status === 401) {
return {};
}
// else set token
// recall old fetch
// here i used 200 because 401 or 404 old response will cause it to rerun
// return fetch(...args); <- change to this for real scenarios
// return fetch(args[0], args[1]); <- or to this for real sceaerios
return fetch(TEMP_API['200'].url, TEMP_API['200'].args);
}
// condition will be tested again after 401 condition and will be ran with old args
if (data.status === 404) {
console.log("==========404 Not Found.=============");
// here i used 200 because 401 or 404 old response will cause it to rerun
// return fetch(...args); <- change to this for real scenarios
// return fetch(args[0], args[1]); <- or to this for real scenarios
return fetch(TEMP_API['200'].url, TEMP_API['200'].args);
sceaerios
} else {
return data;
}
});
};
(async function() {
console.log("==========Example1=============");
let example1 = await fetch(TEMP_API['404'].url, TEMP_API['404'].args);
console.log(example1);
console.log("==========Example2=============");
let example2 = await fetch(TEMP_API['200'].url, TEMP_API['200'].args);
console.log(example2);
console.log("==========Example3=============");
let example3 = await fetch(TEMP_API['401'].url, TEMP_API['401'].args);
console.log(example3);
})();
- 示例 1 向 api 发出 404 状态请求,这将导致 404 条件变为 运行,然后将调用 200 api,之后响应将被 returned
- 向 200 api 发出的示例 2 请求将 return 200 状态代码,这将导致 200 条件通过,并且 运行 和 return 响应
- Example3 向 api 发出 401 状态请求,这将导致 401 条件通过,然后调用 200 api 并打印响应,之后它将超出您可以设置令牌的条件然后将在另一个获取请求中使用
我正在尝试为 javascript 中的获取创建一个拦截器(反应更具体)。它应该从每次调用的提取中获取结果,如果是 401 错误,它应该启动对另一个路由的新提取调用以获取 cookie(刷新令牌)。然后,应该再次尝试原始的提取调用(因为现在用户已登录)。
我已经设法触发了新的获取调用并为每个调用发回了 cookie,但是我遇到了以下两个问题:
我现在不知道如何在收到刷新令牌后重试提取调用。那可能吗?我找到了 fetch-retry npm (https://www.npmjs.com/package/fetch-retry),但不确定在应该为原始 fetch 调用完成时如何以及是否可以在拦截器上实现它。
我似乎对 async await 做错了什么(我认为),因为拦截在 returning 数据(原始状态码)之前不等待 fetch 调用fetch 似乎是 401 而不是 200,我们得到 cookie 后应该是 200。我还尝试 return 拦截器内部 fetch 的响应,但是 returned 未定义)。
知道如何解决这个问题吗?有人做过类似的事情吗?
下面是我的代码:
(function () {
const originalFetch = fetch;
fetch = function() {
return originalFetch.apply(this, arguments).then(function(data) {
if(data.status === 401) {
console.log('not authorized, trying to get refresh cookie..')
const fetchIt = async () => {
let response = await fetch(`/api/token`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
});
}
fetchIt();
}
return data
});
};
})();
编辑:为了更清楚地说明我所追求的。我需要一个像我上面描述的拦截器来工作,这样我就不必在每次 fetch 调用后都做这样的事情:
getData() {
const getDataAsync = async () => {
let response = await fetch(`/api/loadData`, { method: 'POST' });
if(response.status === 401) {
let responseT = await fetch(`/api/token`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
});
if(responseT.status === 401) {
return responseT.status
}
if(responseT.status === 200) {
response = await fetch(`/api/loadData`, { method: 'POST' });
}
}
let data = await response.json();
//Do things with data
};
getDataAsync();
};
所以基本上拦截器应该:
- 检查是否有401,如果有则:
- 获取api/token
- 如果api/token returns 401,它应该return那个。
- 如果api/token returns 200, 应该运行 重新获取原始数据
尝试重新调整获取承诺,而不是等待它。
(function () {
const originalFetch = fetch;
fetch = function () {
return originalFetch.apply(this, arguments).then(function (data) {
if (data.status === 200) console.log("---------Status 200----------");
if (data.status === 404) {
console.log("==========404 Not Found.=============");
return fetch(`https://jsonplaceholder.typicode.com/todos/2`);
} else {
return data;
}
});
};
})();
function test(id) {
//will trigger 404 status
return fetch(`https://jsonplaceholder.typicode.com/todos/` + id, {
method: "POST",
credentials: "include",
});
}
test(1).then((i) => console.log(i));
您可以简单地使用 originalFetch
作为令牌并等待响应,如果响应是 401 那么您只需 return 清空对第一次获取调用的响应,否则您更新令牌然后让它进入下一个条件这将重新运行旧请求。
let TEMP_API = {
'401': {
url: 'https://run.mocky.io/v3/7a98985c-1e59-4bfb-87dd-117307b6196c',
args: {}
},
'200': {
url: 'https://jsonplaceholder.typicode.com/todos/2',
args: {}
},
'404': {
url: 'https://jsonplaceholder.typicode.com/todos/1',
args: {
method: "POST",
credentials: "include"
}
}
}
const originalFetch = fetch;
fetch = function() {
let self = this;
let args = arguments;
return originalFetch.apply(self, args).then(async function(data) {
if (data.status === 200) console.log("---------Status 200----------");
if (data.status === 401) {
// request for token with original fetch if status is 401
console.log('failed');
let response = await originalFetch(TEMP_API['200'].url, TEMP_API['200'].args);
// if status is 401 from token api return empty response to close recursion
console.log("==========401 UnAuthorize.=============");
console.log(response);
if (response.status === 401) {
return {};
}
// else set token
// recall old fetch
// here i used 200 because 401 or 404 old response will cause it to rerun
// return fetch(...args); <- change to this for real scenarios
// return fetch(args[0], args[1]); <- or to this for real sceaerios
return fetch(TEMP_API['200'].url, TEMP_API['200'].args);
}
// condition will be tested again after 401 condition and will be ran with old args
if (data.status === 404) {
console.log("==========404 Not Found.=============");
// here i used 200 because 401 or 404 old response will cause it to rerun
// return fetch(...args); <- change to this for real scenarios
// return fetch(args[0], args[1]); <- or to this for real scenarios
return fetch(TEMP_API['200'].url, TEMP_API['200'].args);
sceaerios
} else {
return data;
}
});
};
(async function() {
console.log("==========Example1=============");
let example1 = await fetch(TEMP_API['404'].url, TEMP_API['404'].args);
console.log(example1);
console.log("==========Example2=============");
let example2 = await fetch(TEMP_API['200'].url, TEMP_API['200'].args);
console.log(example2);
console.log("==========Example3=============");
let example3 = await fetch(TEMP_API['401'].url, TEMP_API['401'].args);
console.log(example3);
})();
- 示例 1 向 api 发出 404 状态请求,这将导致 404 条件变为 运行,然后将调用 200 api,之后响应将被 returned
- 向 200 api 发出的示例 2 请求将 return 200 状态代码,这将导致 200 条件通过,并且 运行 和 return 响应
- Example3 向 api 发出 401 状态请求,这将导致 401 条件通过,然后调用 200 api 并打印响应,之后它将超出您可以设置令牌的条件然后将在另一个获取请求中使用