欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端實(shí)現(xiàn)無(wú)感刷新的詳細(xì)方案

 更新時(shí)間:2025年03月28日 10:18:34   作者:北辰alk  
無(wú)感刷新(Silent Refresh)是指在用戶無(wú)感知的情況下,通過(guò)技術(shù)手段自動(dòng)更新身份憑證(如Token),維持用戶登錄狀態(tài)的技術(shù)方案,本文給大家介紹了前端實(shí)現(xiàn)無(wú)感刷新的詳細(xì)方案,需要的朋友可以參考下

一、什么是無(wú)感刷新?

1.1 核心概念

無(wú)感刷新(Silent Refresh)是指在用戶無(wú)感知的情況下,通過(guò)技術(shù)手段自動(dòng)更新身份憑證(如Token),維持用戶登錄狀態(tài)的技術(shù)方案。主要解決以下痛點(diǎn):

  • 傳統(tǒng)Token過(guò)期強(qiáng)制退出影響用戶體驗(yàn)
  • 減少重復(fù)登錄操作
  • 保持長(zhǎng)期會(huì)話的有效性

1.2 典型應(yīng)用場(chǎng)景

場(chǎng)景說(shuō)明
JWT認(rèn)證Access Token過(guò)期自動(dòng)刷新
OAuth2.0使用Refresh Token獲取新憑證
敏感操作維持長(zhǎng)時(shí)間操作不中斷

二、實(shí)現(xiàn)原理與方案對(duì)比

2.1 技術(shù)方案對(duì)比

方案優(yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景
定時(shí)檢測(cè)實(shí)現(xiàn)簡(jiǎn)單時(shí)間誤差大短期會(huì)話
請(qǐng)求攔截精確控制需要全局處理常規(guī)Web應(yīng)用
Web Worker不阻塞主線程復(fù)雜度高大型應(yīng)用
Service Worker離線可用需要HTTPSPWA應(yīng)用

2.2 核心實(shí)現(xiàn)流程

三、基礎(chǔ)版實(shí)現(xiàn)(Axios攔截器方案)

3.1 創(chuàng)建Axios實(shí)例

// src/utils/request.js
import axios from 'axios'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 10000
})

3.2 添加請(qǐng)求攔截器

// 請(qǐng)求攔截器
service.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('access_token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

3.3 響應(yīng)攔截器處理邏輯

// 響應(yīng)攔截器
let isRefreshing = false
let requests = []

service.interceptors.response.use(
  (response) => {
    return response.data
  },
  async (error) => {
    const { config, response } = error
    
    // Token過(guò)期處理
    if (response.status === 401 && !config._retry) {
      
      // 存儲(chǔ)待重試請(qǐng)求
      if (!isRefreshing) {
        isRefreshing = true
        
        try {
          // 刷新Token
          const newToken = await refreshToken()
          
          // 存儲(chǔ)新Token
          localStorage.setItem('access_token', newToken)
          
          // 重試隊(duì)列
          requests.forEach(cb => cb(newToken))
          requests = []
          
          // 重試原請(qǐng)求
          config.headers.Authorization = `Bearer ${newToken}`
          return service(config)
        } catch (refreshError) {
          // 刷新失敗處理
          localStorage.clear()
          window.location.href = '/login'
          return Promise.reject(refreshError)
        } finally {
          isRefreshing = false
        }
      }
      
      // 將未完成的請(qǐng)求加入隊(duì)列
      return new Promise((resolve) => {
        requests.push((token) => {
          config.headers.Authorization = `Bearer ${token}`
          resolve(service(config))
        })
      })
    }
    
    return Promise.reject(error)
  }
)

3.4 Token刷新函數(shù)

async function refreshToken() {
  const refreshToken = localStorage.getItem('refresh_token')
  if (!refreshToken) {
    throw new Error('缺少刷新令牌')
  }
  
  try {
    const { data } = await axios.post('/api/auth/refresh', {
      refresh_token: refreshToken
    })
    
    return data.access_token
  } catch (error) {
    throw new Error('令牌刷新失敗')
  }
}

四、進(jìn)階優(yōu)化方案

4.1 并發(fā)請(qǐng)求控制

class TokenRefreshManager {
  constructor() {
    this.subscribers = []
    this.isRefreshing = false
  }

  subscribe(callback) {
    this.subscribers.push(callback)
  }

  onRefreshed(token) {
    this.subscribers.forEach(callback => callback(token))
    this.subscribers = []
  }

  async refresh() {
    if (this.isRefreshing) {
      return new Promise(resolve => {
        this.subscribe(resolve)
      })
    }
    
    this.isRefreshing = true
    try {
      const newToken = await refreshToken()
      this.onRefreshed(newToken)
      return newToken
    } finally {
      this.isRefreshing = false
    }
  }
}

export const tokenManager = new TokenRefreshManager()

4.2 定時(shí)檢測(cè)策略

// Token有效期檢測(cè)
function setupTokenCheck() {
  const checkInterval = setInterval(() => {
    const token = localStorage.getItem('access_token')
    if (token && isTokenExpired(token)) {
      tokenManager.refresh().catch(() => {
        clearInterval(checkInterval)
      })
    }
  }, 60 * 1000) // 每分鐘檢查一次
}

// JWT解碼示例
function isTokenExpired(token) {
  const payload = JSON.parse(atob(token.split('.')[1]))
  const exp = payload.exp * 1000
  const now = Date.now()
  return now > exp - 5 * 60 * 1000 // 提前5分鐘刷新
}

4.3 Web Worker實(shí)現(xiàn)

// worker.js
self.addEventListener('message', async (e) => {
  if (e.data.type === 'refreshToken') {
    try {
      const response = await fetch('/api/refresh', {
        method: 'POST',
        body: JSON.stringify({
          refresh_token: e.data.refreshToken
        })
      })
      const data = await response.json()
      self.postMessage({ success: true, token: data.access_token })
    } catch (error) {
      self.postMessage({ success: false, error })
    }
  }
})

// 主線程調(diào)用
const worker = new Worker('./worker.js')

function refreshWithWorker() {
  return new Promise((resolve, reject) => {
    worker.postMessage({
      type: 'refreshToken',
      refreshToken: localStorage.getItem('refresh_token')
    })
    
    worker.onmessage = (e) => {
      if (e.data.success) {
        resolve(e.data.token)
      } else {
        reject(e.data.error)
      }
    }
  })
}

五、安全增強(qiáng)措施

5.1 安全存儲(chǔ)方案

// 安全存儲(chǔ)類
class SecureStorage {
  private encryptionKey: string
  
  constructor(key: string) {
    this.encryptionKey = key
  }

  setItem(key: string, value: string) {
    const encrypted = CryptoJS.AES.encrypt(value, this.encryptionKey)
    localStorage.setItem(key, encrypted.toString())
  }

  getItem(key: string) {
    const encrypted = localStorage.getItem(key)
    if (!encrypted) return null
    
    return CryptoJS.AES.decrypt(encrypted, this.encryptionKey)
      .toString(CryptoJS.enc.Utf8)
  }
}

// 初始化實(shí)例
const storage = new SecureStorage('your-secret-key')
storage.setItem('refresh_token', 'your-refresh-token')

5.2 雙Token校驗(yàn)流程

5.3 防御措施

// 防止CSRF攻擊示例
function addCsrfProtection(config) {
  const csrfToken = getCsrfToken() // 從Cookie獲取
  if (csrfToken) {
    config.headers['X-CSRF-TOKEN'] = csrfToken
  }
  return config
}

// 速率限制
let refreshCount = 0
setInterval(() => {
  refreshCount = Math.max(0, refreshCount - 2)
}, 60 * 1000)

async function safeRefresh() {
  if (refreshCount > 5) {
    throw new Error('刷新過(guò)于頻繁')
  }
  refreshCount++
  return refreshToken()
}

六、多框架適配實(shí)現(xiàn)

6.1 Vue3 Composition API實(shí)現(xiàn)

<script setup>
import { ref } from 'vue'
import { useAxios } from '@vueuse/integrations/useAxios'

const { execute } = useAxios(
  '/api/data',
  { method: 'GET' },
  {
    immediate: false,
    onError: async (error) => {
      if (error.response?.status === 401) {
        await refreshToken()
        execute() // 自動(dòng)重試
      }
    }
  }
)
</script>

6.2 React Hooks實(shí)現(xiàn)

import { useEffect } from 'react'
import axios from 'axios'

function useSilentRefresh() {
  useEffect(() => {
    const interceptor = axios.interceptors.response.use(
      response => response,
      async error => {
        if (error.response.status === 401) {
          await refreshToken()
          return axios.request(error.config)
        }
        return Promise.reject(error)
      }
    )
    
    return () => {
      axios.interceptors.response.eject(interceptor)
    }
  }, [])
}

6.3 Angular攔截器實(shí)現(xiàn)

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    return next.handle(req).pipe(
      catchError(error => {
        if (error.status === 401) {
          return this.auth.refresh().pipe(
            switchMap(() => {
              const authReq = req.clone({
                setHeaders: { Authorization: `Bearer ${this.auth.token}` }
              })
              return next.handle(authReq)
            })
          )
        }
        return throwError(error)
      })
    )
  }
}

七、性能優(yōu)化方案

7.1 請(qǐng)求隊(duì)列管理

class RequestQueue {
  constructor() {
    this.queue = []
    this.isProcessing = false
  }

  add(request) {
    return new Promise((resolve, reject) => {
      this.queue.push({ request, resolve, reject })
      if (!this.isProcessing) this.process()
    })
  }

  async process() {
    this.isProcessing = true
    while (this.queue.length) {
      const { request, resolve, reject } = this.queue.shift()
      try {
        const response = await request()
        resolve(response)
      } catch (error) {
        reject(error)
      }
    }
    this.isProcessing = false
  }
}

7.2 內(nèi)存緩存優(yōu)化

const tokenCache = {
  accessToken: null,
  refreshToken: null,
  expiresAt: 0,

  get access() {
    if (Date.now() < this.expiresAt) {
      return this.accessToken
    }
    return null
  },

  async refresh() {
    const { access_token, expires_in } = await refreshToken()
    this.accessToken = access_token
    this.expiresAt = Date.now() + expires_in * 1000
    return access_token
  }
}

7.3 指數(shù)退避重試

async function retryWithBackoff(fn, retries = 3, delay = 1000) {
  try {
    return await fn()
  } catch (error) {
    if (retries <= 0) throw error
    await new Promise(resolve => setTimeout(resolve, delay))
    return retryWithBackoff(fn, retries - 1, delay * 2)
  }
}

八、生產(chǎn)環(huán)境注意事項(xiàng)

8.1 安全規(guī)范

  1. HTTPS必須啟用:防止中間人攻擊
  2. 設(shè)置合理有效期
    • Access Token:15-30分鐘
    • Refresh Token:7-30天 
  3. 權(quán)限分離:Refresh Token僅用于獲取新Access Token

8.2 監(jiān)控指標(biāo)

指標(biāo)監(jiān)控方式報(bào)警閾值
刷新成功率日志統(tǒng)計(jì)<95%
并發(fā)請(qǐng)求數(shù)性能監(jiān)控>100/秒
Token泄露次數(shù)安全掃描>0次

8.3 災(zāi)備方案

  • 服務(wù)降級(jí):刷新失敗時(shí)保留部分功能
  • 異地多活:認(rèn)證中心多區(qū)域部署
  • 熔斷機(jī)制:異常時(shí)自動(dòng)切換認(rèn)證方式

九、完整實(shí)現(xiàn)流程圖

十、常見(jiàn)問(wèn)題解答

Q1:如何防止Refresh Token被盜用?

  • 綁定設(shè)備指紋
  • 限制使用IP范圍
  • 設(shè)置單次有效性

Q2:移動(dòng)端實(shí)現(xiàn)有何不同?

  • 使用安全存儲(chǔ)(Keychain/Keystore)
  • 結(jié)合生物認(rèn)證
  • 考慮網(wǎng)絡(luò)切換場(chǎng)景

Q3:如何處理多標(biāo)簽頁(yè)場(chǎng)景?

// 使用BroadcastChannel同步狀態(tài)
const channel = new BroadcastChannel('auth')

channel.addEventListener('message', (event) => {
  if (event.data.type === 'token_refreshed') {
    localStorage.setItem('access_token', event.data.token)
  }
})

function broadcastNewToken(token) {
  channel.postMessage({ type: 'token_refreshed', token })
}

十一、總結(jié)與展望

11.1 技術(shù)總結(jié)

  • 實(shí)現(xiàn)核心:請(qǐng)求攔截 + Token刷新隊(duì)列
  • 關(guān)鍵優(yōu)化:并發(fā)控制 + 安全存儲(chǔ)
  • 擴(kuò)展方案:多框架適配 + 性能優(yōu)化

11.2 未來(lái)趨勢(shì)

  1. 無(wú)密碼認(rèn)證:WebAuthn標(biāo)準(zhǔn)普及
  2. 零信任架構(gòu):持續(xù)身份驗(yàn)證
  3. 區(qū)塊鏈身份:去中心化認(rèn)證

以上就是前端實(shí)現(xiàn)無(wú)感刷新的詳細(xì)方案的詳細(xì)內(nèi)容,更多關(guān)于前端無(wú)感刷新的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序如何獲取用戶頭像和昵稱

    微信小程序如何獲取用戶頭像和昵稱

    這篇文章主要介紹了微信小程序如何獲取用戶頭像和昵稱,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • JavaScript調(diào)試之console.log調(diào)試的一個(gè)小技巧分享

    JavaScript調(diào)試之console.log調(diào)試的一個(gè)小技巧分享

    日常開(kāi)發(fā)中經(jīng)常會(huì)需要console來(lái)查看當(dāng)前對(duì)象的值。當(dāng)然用debugger會(huì)更全面的查看,但是總有只喜歡用console的,比如我。下面這篇文章主要給大家分享了關(guān)于JavaScript調(diào)試之console.log調(diào)試的一個(gè)小技巧,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-08-08
  • js如何獲取訪問(wèn)IP、地區(qū)、當(dāng)前操作瀏覽器

    js如何獲取訪問(wèn)IP、地區(qū)、當(dāng)前操作瀏覽器

    這篇文章主要介紹了js如何獲取訪問(wèn)IP、地區(qū)、當(dāng)前操作瀏覽器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 解決bootstrap中modal遇到Esc鍵無(wú)法關(guān)閉頁(yè)面

    解決bootstrap中modal遇到Esc鍵無(wú)法關(guān)閉頁(yè)面

    Bootstrap,來(lái)自 Twitter,是目前最受歡迎的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的,它簡(jiǎn)潔靈活,使得 Web 開(kāi)發(fā)更加快捷。不過(guò)在使用的過(guò)程中,我們還是會(huì)遇到各種小問(wèn)題,今天我們探討的就是個(gè)人在使用中遇到的一個(gè)小BUG的修復(fù)。
    2015-03-03
  • JS 事件冒泡 示例代碼

    JS 事件冒泡 示例代碼

    JS 事件冒泡 示例代碼,大家可以參考下。
    2009-07-07
  • canvas軌跡回放功能實(shí)現(xiàn)

    canvas軌跡回放功能實(shí)現(xiàn)

    這篇文章主要介紹了canvas軌跡回放功能實(shí)現(xiàn)過(guò)程以及相關(guān)的代碼整理,跟著小編一起學(xué)習(xí)下吧。
    2017-12-12
  • js中實(shí)現(xiàn)多態(tài)采用和繼承類似的方法

    js中實(shí)現(xiàn)多態(tài)采用和繼承類似的方法

    首先定義一個(gè)抽象類,其中調(diào)用一些虛方法,虛方法在抽象類中沒(méi)用定義,而是通過(guò)其具體的實(shí)現(xiàn)類來(lái)實(shí)現(xiàn)
    2014-08-08
  • JavaScript設(shè)計(jì)模式之單例模式詳解

    JavaScript設(shè)計(jì)模式之單例模式詳解

    單例模式(Singleton Pattern)是一種創(chuàng)建型設(shè)計(jì)模式,確保一個(gè)類只有一個(gè)實(shí)例,并提供全局訪問(wèn)該實(shí)例的方式,這在某些場(chǎng)景下非常有用,例如配置管理類、日志類或數(shù)據(jù)庫(kù)連接管理類,需要的朋友可以參考下
    2024-08-08
  • thinkjs微信中控之微信鑒權(quán)登陸的實(shí)現(xiàn)代碼

    thinkjs微信中控之微信鑒權(quán)登陸的實(shí)現(xiàn)代碼

    這篇文章主要介紹了thinkjs微信中控之微信鑒權(quán)登陸的實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 前端GET/POST請(qǐng)求下載文件多種方式代碼示例

    前端GET/POST請(qǐng)求下載文件多種方式代碼示例

    文件都是通過(guò)接口獲取的,前端通過(guò)調(diào)用接口將接口返回的文件下載,下面這篇文章主要給大家介紹了關(guān)于前端GET/POST請(qǐng)求下載文件的多種方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06

最新評(píng)論