gpt4 book ai didi

javascript - 包装 javascript fetch 以添加自定义功能

转载 作者:行者123 更新时间:2023-11-29 23:54:27 25 4
gpt4 key购买 nike

我想知道是否可以这样做,因为我不确定我是错了还是不可能。基本上,我想做的是为原生 fetch javascript 函数创建一个包装函数。此包装函数将实现 token 验证过程,如果给定的已过期并再次请求所需资源,则请求新的 accessToken。这是我到目前为止所达到的:

customFetch.js

// 'url' and 'options' parameters are used strictely as you would use them in fetch. 'authOptions' are used to configure the call to refresh the access token
window.customFetch = (url, options, authOptions) => {

const OPTIONS = {
url: '',
unauthorizedRedirect: '',
storage: window.sessionStorage,
tokenName: 'accessToken'
}

// Merge options passed by user with the default auth options
let opts = Object.assign({}, OPTIONS, authOptions);

// Try to update 'authorizarion's header in order to send always the proper one to the server
options.headers = options.headers || {};
options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`;

// Actual server request that user wants to do.
const request = window.fetch(url, options)
.then((d) => {
if (d.status === 401) {
// Unauthorized
console.log('not authorized');
return refreshAccesToken();
}
else {
return d.json();
}
});

// Auxiliar server call to get refresh the access token if it is expired. Here also check if the
// cookie has expired and if it has expired, then we should redirect to other page to login again in
// the application.
const refreshAccesToken = () => {
window.fetch(opts.url, {
method: 'get',
credentials: 'include'
}).then((d) => {
// For this example, we can omit this, we can suppose we always receive the access token
if (d.status === 401) {
// Unauthorized and the cookie used to validate and refresh the access token has expired. So we want to login in to the app again
window.location.href = opts.unauthorizedRedirect;
}

return d.json();
}).then((json) => {
const jwt = json.token;
if (jwt) {
// Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request
opts.storage.setItem(opts.tokenName, jwt);
console.log('new acces token: ' + jwt);

// Re-send the original request when we have received the refreshed access token.
return window.customFetch(url, options, authOptions);
}
else {
console.log('no token has been sent');
return null;
}
});
}

return request;
}

消费者.js

const getResourcePrivate = () => {
const url = MAIN_URL + '/resource';
customFetch(url, {
method: 'get'
},{
url: AUTH_SERVER_TOKEN,
unauthorizedRedirect: AUTH_URI,
tokenName: TOKEN_NAME
}).then((json) => {
const resource = json ? json.resource : null;
if (resource) {
console.log(resource);
}
else {
console.log('No resource has been provided.');
}
});
}

我会尝试更好地解释上面的代码:我想让用户对 token 验证透明,以便让他们只担心请求他们想要的资源。当 accessToken 仍然有效时,此方法工作正常,因为 return request 指令向消费者提供了 fetch 请求的 promise 。

当然,当 accessToken 过期并且我们向 auth 服务器请求一个新的时,这是行不通的。刷新 token 并请求私有(private)资源,但 consumer.js 看不到它。

对于最后一个场景,是否可以修改程序流程,以便刷新accessToken 并执行服务器调用以再次获取私有(private)资源?消费者不应该意识到这个过程;在这两种情况下(accessToken 有效并且 accessToken 已过期并已刷新)consumer.js 应该在其 中获取私有(private)请求资源code>then 函数。

最佳答案

好吧,我终于找到了解决方案。我尝试使用 Promise 来解决它并且它有效。以下是 customFetch.js 文件的方法:

window.customFetch = (url, options, authOptions) => {

const OPTIONS = {
url: '',
unauthorizedRedirect: '',
storage: window.sessionStorage,
tokenName: 'accessToken'
}

// Merge options passed by user with the default auth options
let opts = Object.assign({}, OPTIONS, authOptions);

const requestResource = (resolve) => {
// Try to update 'authorizarion's header in order to send always the proper one to the server
options.headers = options.headers || {};
options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`;

window.fetch(url, options)
.then((d) => {
if (d.status === 401) {
// Unauthorized
console.log('not authorized');
return refreshAccesToken(resolve);
}
else {
resolve(d.json());
}
});
}

// Auxiliar server call to get refresh the access token if it is expired. Here also check if the
// cookie has expired and if it has expired, then we should redirect to other page to login again in
// the application.
const refreshAccesToken = (resolve) => {
window.fetch(opts.url, {
method: 'get',
credentials: 'include'
}).then((d) => {
if (d.status === 401) {
// Unauthorized
window.location.href = opts.unauthorizedRedirect;
}

return d.json();
}).then((json) => {
const jwt = json.token;
if (jwt) {
// Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request
opts.storage.setItem(opts.tokenName, jwt);
console.log('new acces token: ' + jwt);

// Re-send the original request when we have received the refreshed access token.
requestResource(resolve);
}
else {
console.log('no token has been sent');
return null;
}
});
}

let promise = new Promise((resolve, reject) => {
requestResource(resolve);
});

return promise;
}

基本上,我创建了一个 Promise 并在其中调用了调用服务器以获取资源的函数。我对 request(现在称为 requestResource)和 refreshAccessToken 做了一些修改,以使它们成为可参数化的函数。我已将 resolve 函数传递给他们,以便在我收到新 token 后“解析”任何函数。

可能该解决方案可以改进和优化,但作为第一种方法,它按我预期的方式工作,所以我认为这是一个有效的解决方案。

编辑:正如@Dennis 向我建议的那样,我在最初的方法中犯了一个错误。我只需要在 refreshAccessToken 函数中返回 promise ,它就可以正常工作。这就是 customFetch.js 文件的外观(这与我第一次发布的代码更相似。事实上,我只是在函数中添加了一个 return 指令, 尽管删除开始和结束括号也可以):

// 'url' and 'options' parameters are used strictely as you would use them in fetch. 'authOptions' are used to configure the call to refresh the access token
window.customFetch = (url, options, authOptions) => {

const OPTIONS = {
url: '',
unauthorizedRedirect: '',
storage: window.sessionStorage,
tokenName: 'accessToken'
}

// Merge options passed by user with the default auth options
let opts = Object.assign({}, OPTIONS, authOptions);

// Try to update 'authorizarion's header in order to send always the proper one to the server
options.headers = options.headers || {};
options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`;

// Actual server request that user wants to do.
const request = window.fetch(url, options)
.then((d) => {
if (d.status === 401) {
// Unauthorized
console.log('not authorized');
return refreshAccesToken();
}
else {
return d.json();
}
});

// Auxiliar server call to get refresh the access token if it is expired. Here also check if the
// cookie has expired and if it has expired, then we should redirect to other page to login again in
// the application.
const refreshAccesToken = () => {
return window.fetch(opts.url, {
method: 'get',
credentials: 'include'
}).then((d) => {
// For this example, we can omit this, we can suppose we always receive the access token
if (d.status === 401) {
// Unauthorized and the cookie used to validate and refresh the access token has expired. So we want to login in to the app again
window.location.href = opts.unauthorizedRedirect;
}

return d.json();
}).then((json) => {
const jwt = json.token;
if (jwt) {
// Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request
opts.storage.setItem(opts.tokenName, jwt);
console.log('new acces token: ' + jwt);

// Re-send the original request when we have received the refreshed access token.
return window.customFetch(url, options, authOptions);
}
else {
console.log('no token has been sent');
return null;
}
});
}

return request;
}

关于javascript - 包装 javascript fetch 以添加自定义功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42068193/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com