You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:45:20