首頁 > 軟體

關於401狀態碼的含義和處理方式

2022-08-16 14:02:58

401狀態碼的含義和處理

401狀態碼的含義

axios向伺服器端傳送請求時,有兩種情況會出現401狀態碼(unauthorized未授權):

1. 伺服器端要求傳遞token資訊,而實際傳送請求時沒有傳遞。

2. 傳送請求時有傳遞token到達伺服器端,但由於時間比較久,這個token在伺服器中已經過期了(伺服器儲存token有效期時間為2個小時)。

總之,伺服器端有些api介面要求傳遞token,token失效或沒有傳遞,就會報401錯誤。

401狀態碼的處理

1. 在axios請求攔截器中做token傳遞操作。

2. 可以這樣設定,在axios響應攔截器中判斷請求狀態如果是401,就強制使用者重新登入系統。

第2種情況處理實現:

在axios的響應攔截器中,判斷錯誤碼等於401就強制登入(utils/ax.js)

// 引入路由
import router from '@/router'
// 設定響應攔截器
axios.interceptors.response.use(function (response) {
  // 正常響應處理
  return response
}, function (error) {
  // 非正常響應處理(包括401)
  // console.dir(error) // 物件: config request response isAxiosError toJSON
  if (error.response.status === 401) {
    // token失效(token在伺服器端已經失效了,2個小時時效)
    // 強制使用者重新登入系統,以重新整理伺服器端的token時效
    router.push('/login')
    // 不要給做錯誤提示了
    return new Promise(function () {}) // 空的Promise物件,沒有機會執行catch,進而不做錯誤提示了
  }
  // return new Promise((resolve,reject)=>{
  // reject('獲得文章失敗!')
  // })
  return Promise.reject(error)
})

注意:

1. 路由物件.push(xxx) 可以實現程式設計式導航。

2. 路由物件:在元件中是 this.$router ,在main.js/ax.js檔案中就是router物件(需要import匯入)。

模擬伺服器端token失效步驟:

1. 刪除使用者端sessionStorage資料。

2. 暫時遮蔽守衛程式碼(開發完畢再開啟)。

401狀態碼升級處理

401狀態碼

axios向伺服器端傳送請求時有兩種情況會出現401狀態碼(unauthorized未授權):

1. 伺服器端要求傳遞token資訊,而實際沒有傳遞。

2. 有傳遞token到達伺服器端,但由於時間比較久,這個token在伺服器中已經過期了(伺服器儲存token有效期時間為2個小時)。

總之,伺服器端有些api介面要求傳遞token,token失效或沒有傳遞,就會報401錯誤。

相關處理

1. 第1種情況,可以在axios請求攔截器中做token傳遞操作。

2. 第2種情況,之前是這樣處理的,在axios響應攔截器中判斷請求狀態如果是401,就強制使用者重新登入系統

這樣處理使用者體驗非常不好,現在做一次升級優化處理。 

伺服器端返回兩個祕鑰資訊,它們在伺服器端都有使用時效:

  • token 有效期2小時。
  • refresh_token 有效期14天,refresh_token用於在token過期後,重新獲取並重新整理token時效使用的。

針對第2種401狀態碼處理步驟為:

1. 判斷refresh_token是否存在

不存在就直接重新登入。

存在,axios發起請求,帶著refresh_token請求伺服器端,獲取新token出來:

成功:對vuex和localStorage進行token資訊更新。

失敗:清空無效使用者資訊,直接重新登入。

範例程式碼1 

// 響應攔截器 (響應成功:剝離無效資料,響應失敗:重新整理token)
instance.interceptors.response.use(res => {
  // 將來獲取資料:res.data.data 麻煩
  // 想要結果:data 即可
  try {
    return res.data.data
  } catch (e) {
    return res
  }
}, async err => {
  try {
    // 目的:重新整理token
    if (err.response && err.response.status === 401) {
    // 未登入  跳轉登入頁面  阻止程式執行
      const { user } = store.state
      // 如果沒有token沒登入  如果沒有refresh_token無法重新整理token
      if (!user.token || !user.refresh_token) {
        router.push('/login')
        return Promise.reject(err)
      }
      // 重新整理token,發請求,沒有設定的axios,自己設定refresh_token
      const res = await axios({
        url: 'http://ttapi.research.itcast.cn/app/v1_0/authorizations',
        method: 'put',
        headers: {
          Authorization: `Bearer ${user.refresh_token}`
        }
      })
      // token獲取  res.data.data.token
      // 更新 vuex 和 本地 token
      store.commit('setUser', {
        token: res.data.data.token,
        refresh_token: user.refresh_token
      })
      // 繼續傳送剛才錯誤的請求
      // instance({之前錯誤的請求設定})
      // err錯誤物件 包含(response 響應物件 |config 請求設定)
      return instance(err.config)
    }
  } catch (e) { // exception 異常
    // 重新整理token失敗
    router.push('/login')
    return Promise.reject(e)
  }
  return Promise.reject(err)
})

演示程式碼:promise錯誤處理:

範例程式碼2

import store from '@/store' // 引入vuex中的store範例
import router from '@/router' // 引入路由物件範例
……
// 響應攔截器
instance.interceptors.response.use(
  function (response) {
    try {
      // 返回具體有價值的業務資料
      return response.data.data
    } catch (error) {
      return response.data
    }
  },
  async function (error) {
    // 響應有錯誤,有可能錯誤狀態碼為401
    if (error.response && error.response.status === 401) {
      // 定義登入路由物件
      let toPath = {
        name: 'login',
        query: { redirectUrl: router.currentRoute.path }
      } // 跳轉物件
      // 如果refresh_token不存在
      if (!store.state.user.refresh_token) {
        router.push(toPath)
        return Promise.reject(error)
      }
      try {
        // 重新整理使用者token
        // 應該傳送一個請求 換取新的token
        // 這裡不應該再用instance  因為 instance會再次進入攔截器  用預設的axios
        let result = await axios({
          method: 'put',
          url: 'http://ttapi.research.itcast.cn/app/v1_0/authorizations',
          headers: {
            Authorization: `Bearer ${store.state.user.refresh_token}`
          }
        })
        // 獲取到新token後,就對vuex和localStorage進行更新
        store.commit('updateUser', {
          token: result.data.data.token, // 拿到新的token之後
          refresh_token: store.state.user.refresh_token // 將之前 refresh_token 14天有效期
        })
        return instance(error.config) // 把剛才錯誤的請求再次傳送出去 然後將promise返回
      } catch (err) {
        // 如果錯誤 表示補救措施也沒用了(有可能refresh_token也失效了)
        // 應該跳轉到登入頁 並且 把廢掉的使用者資訊全都幹掉
        store.commit('clearUser') // 所有的使用者資訊清空
        router.push(toPath) // 跳轉到回登入頁
        return Promise.reject(err)
      }
    }
    return Promise.reject(error)
  }
)
') // 所有的使用者資訊清空
        router.push(toPath) // 跳轉到回登入頁
        return Promise.reject(err)
      }
    }
    return Promise.reject(error)
  }
)

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。 


IT145.com E-mail:sddin#qq.com