Skip to content

useTokenRefresh

Token 自动刷新 Composable,用于在 Token 即将过期时自动刷新。

介绍

useTokenRefresh 提供了 Token 自动刷新的功能,可以在 Token 即将过期时自动调用刷新接口,避免用户因 Token 过期而被强制退出登录。

使用方式

typescript
import { useTokenRefresh } from '@/composables'

const { startRefresh, stopRefresh, refreshToken } = useTokenRefresh()

// 启动自动刷新
startRefresh()

// 停止自动刷新
stopRefresh()

// 手动刷新
refreshToken()

API

返回值

名称类型说明
startRefresh() => void启动自动刷新
stopRefresh() => void停止自动刷新
refreshToken() => Promise<void>手动刷新 Token

startRefresh

启动 Token 自动刷新功能。

typescript
function startRefresh(): void

示例

typescript
import { useTokenRefresh } from '@/composables'

const { startRefresh } = useTokenRefresh()

// 在用户登录成功后启动
onMounted(() => {
  startRefresh()
})

stopRefresh

停止 Token 自动刷新功能。

typescript
function stopRefresh(): void

示例

typescript
import { useTokenRefresh } from '@/composables'

const { stopRefresh } = useTokenRefresh()

// 在用户退出登录时停止
function logout() {
  stopRefresh()
  // ... 其他退出逻辑
}

refreshToken

手动刷新 Token。

typescript
function refreshToken(): Promise<void>

示例

typescript
import { useTokenRefresh } from '@/composables'

const { refreshToken } = useTokenRefresh()

// 手动刷新
async function handleRefresh() {
  try {
    await refreshToken()
    ElMessage.success('Token 刷新成功')
  } catch (error) {
    ElMessage.error('Token 刷新失败')
  }
}

完整示例

在登录组件中使用

vue
<script setup lang="ts">
import { useTokenRefresh } from '@/composables'
import { useUserStore } from '@/store/modules/user'

const userStore = useUserStore()
const { startRefresh, stopRefresh } = useTokenRefresh()

// 登录
async function handleLogin() {
  try {
    await userStore.login(loginForm)

    // 登录成功后启动自动刷新
    startRefresh()

    router.push('/')
  } catch (error) {
    console.error('登录失败', error)
  }
}

// 退出登录
async function handleLogout() {
  try {
    // 退出前停止自动刷新
    stopRefresh()

    await userStore.logout()

    router.push('/login')
  } catch (error) {
    console.error('退出失败', error)
  }
}
</script>

在全局路由守卫中使用

typescript
// router/index.ts
import { useTokenRefresh } from '@/composables'

const { startRefresh } = useTokenRefresh()

router.beforeEach((to, from, next) => {
  const token = getToken()

  if (token && to.path !== '/login') {
    // 如果已登录且不是去登录页,启动自动刷新
    startRefresh()
  }

  next()
})

配置

可以在环境变量中配置刷新时间:

bash
# .env.development
# Token 刷新间隔(毫秒)
VITE_TOKEN_REFRESH_INTERVAL = 3600000

注意事项

1. 生命周期

  • 在用户登录成功后调用 startRefresh()
  • 在用户退出登录时调用 stopRefresh()
  • 组件卸载时会自动清理定时器

2. 刷新策略

  • 默认在 Token 即将过期前 5 分钟开始刷新
  • 刷新失败会自动重试
  • 连续失败 3 次后停止刷新并退出登录

3. 并发请求

  • 使用请求锁避免并发刷新
  • 同时有多个请求需要刷新时,只发起一次刷新请求

源码参考

typescript
// composables/auth/useTokenRefresh.ts
export function useTokenRefresh() {
  let refreshTimer: number | null = null
  let isRefreshing = false

  function startRefresh() {
    if (refreshTimer) return

    // 每小时刷新一次
    refreshTimer = window.setInterval(() => {
      refreshToken()
    }, 3600000)
  }

  function stopRefresh() {
    if (refreshTimer) {
      clearInterval(refreshTimer)
      refreshTimer = null
    }
  }

  async function refreshToken() {
    if (isRefreshing) return

    isRefreshing = true
    try {
      const res = await AuthAPI.refreshToken()
      setToken(res.data.token)
    } catch (error) {
      console.error('Token 刷新失败', error)
    } finally {
      isRefreshing = false
    }
  }

  onUnmounted(() => {
    stopRefresh()
  })

  return {
    startRefresh,
    stopRefresh,
    refreshToken
  }
}

相关链接

基于 MIT 许可发布