Fetch调用执行顺序异常:JWT过期后如何正确重试数据请求
问题描述
在单页应用中通过Fetch从API获取数据,需求是:若JWT过期,先请求API获取新JWT,再重新发起数据请求。
尝试用三个函数实现:getData调用fetchData,当fetchData返回409状态(JWT过期)时,调用getjwt函数,之后再次调用fetchData。
现有getjwt函数:
async function getjwt() { // posts a refresh token and gets a jwt in headers let adresse = `${baseUrl}/auth/getjwt` let headers = { 'Content-Type': 'application/json' } postData(adresse, refresh.value, headers) .then((response) => { if (response.status === 200) { jwt.value = response.headers.get('__auth__') } }) .catch((err) => alert(err)) }
以及fetchData和getData函数:
async function fetchData (url = '', headers = {}) { let r = await fetch(url, { method: 'GET', mode: 'cors', cache: 'no-cache', credentials: 'include', headers: headers, redirect: 'follow', referrerPolicy: 'no-referrer', }) return r } async function getData(url = '', headers = {}) { let r = await fetchData(url, headers) if (r.status === 409) { console.log("Oh no! My token has expired.") getjwt() let r = await fetchData(url, headers) return r.json() } return r.json() }
刻意让首次调用fetchData时JWT已过期,getjwt能正确更新Pinia存储中的JWT,但执行顺序异常:getData两次调用fetchData后,getjwt才执行。
问题:如何让getjwt完成新JWT获取后,再执行第二次fetchData?
解决方案
问题核心是异步操作的等待逻辑没处理对,两个关键修复点:
1. 修复getjwt函数,让它返回可等待的Promise
原函数内部用.then()处理异步但没有返回Promise,也没使用await,导致函数会直接结束,上层无法等待它完成。修改后:
async function getjwt() { // posts a refresh token and gets a jwt in headers let adresse = `${baseUrl}/auth/getjwt` let headers = { 'Content-Type': 'application/json' } try { const response = await postData(adresse, refresh.value, headers) if (response.status === 200) { jwt.value = response.headers.get('__auth__') } } catch (err) { alert(err) throw err // 抛出错误,让上层能捕获处理 } }
用await替代.then(),同时通过try/catch处理错误并抛出,避免后续流程在获取JWT失败时继续执行。
2. 在getData中等待getjwt完成,同时更新请求头
原函数调用getjwt时没加await,导致直接执行第二次fetchData,此时新JWT还没更新。另外要注意更新请求头里的JWT,否则第二次请求还是用旧token:
async function getData(url = '', headers = {}) { let r = await fetchData(url, headers) if (r.status === 409) { console.log("Oh no! My token has expired.") await getjwt() // 等待新JWT获取完成 // 更新请求头中的JWT headers['Authorization'] = `Bearer ${jwt.value}` r = await fetchData(url, headers) return r.json() } return r.json() }
额外优化:处理二次请求仍失败的情况
如果refresh token也过期,第二次请求还是会返回409,此时需要引导用户重新登录:
async function getData(url = '', headers = {}) { let r = await fetchData(url, headers) if (r.status === 409) { console.log("Oh no! My token has expired.") try { await getjwt() headers['Authorization'] = `Bearer ${jwt.value}` r = await fetchData(url, headers) if (r.status === 409) { alert("登录已过期,请重新登录") window.location.href = '/login' // 跳转到登录页 return Promise.reject(new Error('登录过期')) } return r.json() } catch (err) { return Promise.reject(err) } } return r.json() }
内容的提问来源于stack exchange,提问作者thiebo
相关产品推荐
相关产品推荐

