vue--axios 攔截器的簡單介紹及使用場景


1.axios 攔截器簡單介紹

// 添加一個請求攔截器
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });
// 添加一個響應攔截器
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });

如果之后想移除攔截器你可以這么做

var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

2.vue 添加 axios 攔截器

1. 安裝 axios

npm install axios --save-dev

2. 新建文件 axios.js

import axios from 'axios'
// 配置默認的 host, 假如你的 API host 是: http://api.htmlx.club
axios.defaults.baseURL = 'http://api.htmlx.club'
// 添加請求攔截器
axios.interceptors.request.use(function (config) {
  // 在發送請求之前做些什么
  return config
}, function (error) {
  // 對請求錯誤做些什么
return Promise.reject(error)
});
// 添加響應攔截器
axios.interceptors.response.use(function (response) {
  // 對響應數據做點什么
  return response
}, function (error) {
  // 對響應錯誤做點什么
  return Promise.reject(error)
});

3. 在 main.js 中進行引用, 並配置一個別名 ($ajax) 來進行調用:

import axios from 'axios'
import '../axios.js'    //axios.js 的路徑
Vue.prototype.$ajax = axios

4. 應用, 一個登錄的 post 如:

this.$ajax({
  method: 'post',
  url: '/login',
  data: {
    'userName': 'xxx',
    'password': 'xxx'
  }
}).then(res => {
  console.log(res)
})

3. 使用場景

3.1 axios 攔截器對路由進行攔截

針對登錄攔截邏輯來看一下

1. 路由攔截

首先在定義路由的時候就需要多添加一個自定義字段 requireAuth, 用於判斷該路由的訪問是否需要登錄. 如果用戶已經登錄, 則順利進入路由, 否則就進入登錄頁面.

const routes = [
    {
        path: '/',
        name: '/',
        component: Index
    },
    {
        path: '/repository',
        name: 'repository',
        meta: {
            requireAuth: true,  // 添加該字段, 表示進入這個路由是需要登錄的
        },
        component: Repository
    },
    {
        path: '/login',
        name: 'login',
        component: Login
    }
];

定義完路由后, 我們主要是利用 vue-router 提供的鈎子函數 beforeEach()對路由進行判斷.

router.beforeEach((to, from, next) => {
    if (to.meta.requireAuth) {  // 判斷該路由是否需要登錄權限
        if (store.state.token) {  // 通過 vuex state 獲取當前的 token 是否存在
            next();
        }
        else {
            next({
                path: '/login',
                query: {redirect: to.fullPath}  // 將跳轉的路由 path 作為參數, 登錄成功后跳轉到該路由
            })
        }
    }
    else {
        next();
    }
}

其中, to.meta 中是我們自定義的數據, 其中就包括我們剛剛定義的 requireAuth 字段. 通過這個字段來判斷該路由是否需要登錄權限. 需要的話, 同時當前應用不存在 token, 則跳轉到登錄頁面, 進行登錄. 登錄成功后跳轉到目標路由.

登錄攔截到這里就結束了嗎? 並沒有. 這種方式只是簡單的前端路由控制, 並不能真正阻止用戶訪問需要登錄權限的路由. 還有一種情況便是: 當前 token 失效了, 但是 token 依然保存在本地. 這時候你去訪問需要登錄權限的路由時, 實際上應該讓用戶重新登錄.

這時候就需要結合 http 攔截器 + 后端接口返回的 http 狀態碼來判斷.

2. 攔截器

要想統一處理所有 http 請求和響應, 就得用上 axios 的攔截器. 通過配置 http response inteceptor, 當后端接口返回 401 Unauthorized(未授權), 讓用戶重新登錄.

// http request 攔截器
axios.interceptors.request.use(
    config => {
        if (store.state.token) {  // 判斷是否存在 token, 如果存在的話, 則每個 http header 都加上 token
            config.headers.Authorization = `token ${store.state.token}`;
        }
        return config;
    },
    err => {
        return Promise.reject(err);
    });
// http response 攔截器
axios.interceptors.response.use(
    response => {
        return response;
    },
    error => {
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    // 返回 401 清除 token 信息並跳轉到登錄頁面
                    store.commit(types.LOGOUT);
                    router.replace({
                        path: 'login',
                        query: {redirect: router.currentRoute.fullPath}
                    })
            }
        }
        return Promise.reject(error.response.data)   // 返回接口返回的錯誤信息
    });

3.2 axios 攔截器對 http 請求的響應狀態統一進行處理

首先我們要明白設置攔截器的目的是什么, 當我們需要統一處理 http 請求和響應時我們通過設置攔截器處理方便很多.

這個項目我引入了 element ui 框架, 所以我是結合 element 中 loading 和 message 組件來處理的. 我們可以單獨建立一個 http 的 js 文件處理 axios, 再到 main.js 中引入.

/**
 * http 配置
 */
// 引入 axios 以及 element ui 中的 loading 和 message 組件
import axios from 'axios'
import { Loading, Message } from 'element-ui'
// 超時時間
axios.defaults.timeout = 5000
// http 請求攔截器
var loadinginstace
axios.interceptors.request.use(config => {
 // element ui Loading 方法
 loadinginstace = Loading.service({ fullscreen: true })
 return config
}, error => {
 loadinginstace.close()
 Message.error({
 message: '加載超時'
 })
 return Promise.reject(error)
})
// http 響應攔截器
axios.interceptors.response.use(data => {// 響應成功關閉 loading
 loadinginstace.close()
 return data
}, error => {
 loadinginstace.close()
 Message.error({
 message: '加載失敗'
 })
 return Promise.reject(error)
})
export default axios

3.3 axios 攔截器對重復請求的處理

axios 官方文檔上給了兩種取消請求的方式.

輕查看: vue axios 在切換路由時如何取消所有請求 --cancelToken

根據文檔上的第二種方法, 我們可以在攔截器里統一處理取消重復請求

let pending = []; // 聲明一個數組用於存儲每個 ajax 請求的取消函數和 ajax 標識
let cancelToken = axios.CancelToken;
let removePending = (config) => {
    for(let p in pending){
        if(pending[p].u === config.url + '&' + config.method) { // 當當前請求在數組中存在時執行函數體
            pending[p].f(); // 執行取消操作
            pending.splice(p, 1); // 把這條記錄從數組中移除
        }
    }
}
// 添加請求攔截器
axios.interceptors.request.use(config=>{
     removePending(config); // 在一個 ajax 發送前執行一下取消操作
     config.cancelToken = new cancelToken((c)=>{
        // 這里的 ajax 標識我是用請求地址 & 請求方式拼接的字符串, 當然你可以選擇其他的一些方式
        pending.push({ u: config.url + '&' + config.method, f: c });
    });
     return config;
   },error => {
     return Promise.reject(error);
   });
// 添加響應攔截器
axios.interceptors.response.use(response=>{
      removePending(res.config);  // 在一個 ajax 響應后再執行一下取消操作, 把已經完成的請求從 pending 中移除
      return response;
   },error =>{

return { data: { } }; 返回一個空對象, 主要是防止控制台報錯

});

同一個請求, 沒有完成的請求將被取消

利用這個方法, 一方面可以防止重復點擊不同頁碼導致的表格數據閃爍, 另外可以做實時搜索, 始終獲取最新結果.

 

最后取消重復請求會有些問題. 第二次請求時后台已經接收到了請求. 還是會生成 2 次相同的數據. 下面是對應的處理:

let pending = []
let CancelToken = axios.CancelToken
let removePending = (config, f) => {
    let flagUrl = config.url + '&' + config.method
        if (pending.indexOf(flagUrl) !== -1) {
            if (f) {
                f() // 執行取消操作
            } else {
                pending.splice(pending.indexOf(flagUrl), 1)// 把這條記錄從數組中移除
            }
        } else {
        if (f) {
            pending.push(flagUrl)
        }
    }
}
// http request 攔截器
HTTP.interceptors.request.use(
config => {
    if (config.method === 'post') {
        console.log('我是攔截')
        config.cancelToken = new CancelToken((c) => {
            removePending(config, c)
        })
    }
    return config
},
err => {
    return Promise.reject(err)
})
// http response 攔截器
HTTP.interceptors.response.use(
response => {
    if (response.config.method === 'post') {
        removePending(response.config)
    }
    return response
},
error => {
    pending = []
    return { data: {error: error} } // 返回接口返回的錯誤信息
})

第一種適合 tabs, 分頁等快速來回點擊的情況, 取消之前的請求, 保持最近的一次請求.

第二種適合相同的接口被請求了多次, 只留第一次, 其他的都取消請求.

 

https://www.h3399.cn/201805/582452.html

1.axios 攔截器簡單介紹

  1. // 添加一個請求攔截器
  2. axios.interceptors.request.use(function(config){
  3. // Do something before request is sent
  4. return config;
  5. },function(error){
  6. // Do something with request error
  7. returnPromise.reject(error);
  8. });
  9. // 添加一個響應攔截器
  10. axios.interceptors.response.use(function(response){
  11. // Do something with response data
  12. return response;
  13. },function(error){
  14. // Do something with response error
  15. returnPromise.reject(error);
  16. });

如果之后想移除攔截器你可以這么做

  1. var myInterceptor = axios.interceptors.request.use(function(){/*...*/});
  2. axios.interceptors.request.eject(myInterceptor);

2.vue 添加 axios 攔截器

1. 安裝 axios

npm install axios --save-dev

2. 新建文件 axios.js

  1. import axios from'axios'
  2. // 配置默認的 host, 假如你的 API host 是: http://api.htmlx.club
  3. axios.defaults.baseURL ='http://api.htmlx.club'
  4. // 添加請求攔截器
  5. axios.interceptors.request.use(function(config){
  6. // 在發送請求之前做些什么
  7. return config
  8. },function(error){
  9. // 對請求錯誤做些什么
  10. returnPromise.reject(error)
  11. });
  12. // 添加響應攔截器
  13. axios.interceptors.response.use(function(response){
  14. // 對響應數據做點什么
  15. return response
  16. },function(error){
  17. // 對響應錯誤做點什么
  18. returnPromise.reject(error)
  19. });

3. 在 main.js 中進行引用, 並配置一個別名 ($ajax) 來進行調用:

  1. import axios from'axios'
  2. import'../axios.js'//axios.js 的路徑
  3. Vue.prototype.$ajax = axios

4. 應用, 一個登錄的 post 如:

  1. this.$ajax({
  2. method:'post',
  3. url:'/login',
  4. data:{
  5. 'userName':'xxx',
  6. 'password':'xxx'
  7. }
  8. }).then(res =>{
  9. console.log(res)
  10. })

3. 使用場景

3.1 axios 攔截器對路由進行攔截

針對登錄攔截邏輯來看一下

1. 路由攔截

首先在定義路由的時候就需要多添加一個自定義字段 requireAuth, 用於判斷該路由的訪問是否需要登錄. 如果用戶已經登錄, 則順利進入路由, 否則就進入登錄頁面.

  1. const routes =[
  2. {
  3. path:'/',
  4. name:'/',
  5. component:Index
  6. },
  7. {
  8. path:'/repository',
  9. name:'repository',
  10. meta:{
  11. requireAuth:true,// 添加該字段, 表示進入這個路由是需要登錄的
  12. },
  13. component:Repository
  14. },
  15. {
  16. path:'/login',
  17. name:'login',
  18. component:Login
  19. }
  20. ];

定義完路由后, 我們主要是利用 vue-router 提供的鈎子函數 beforeEach()對路由進行判斷.

  1. router.beforeEach((to,from,next)=>{
  2. if(to.meta.requireAuth){// 判斷該路由是否需要登錄權限
  3. if(store.state.token){// 通過 vuex state 獲取當前的 token 是否存在
  4. next();
  5. }
  6. else{
  7. next({
  8. path:'/login',
  9. query:{redirect: to.fullPath}// 將跳轉的路由 path 作為參數, 登錄成功后跳轉到該路由
  10. })
  11. }
  12. }
  13. else{
  14. next();
  15. }
  16. })

其中, to.meta 中是我們自定義的數據, 其中就包括我們剛剛定義的 requireAuth 字段. 通過這個字段來判斷該路由是否需要登錄權限. 需要的話, 同時當前應用不存在 token, 則跳轉到登錄頁面, 進行登錄. 登錄成功后跳轉到目標路由.

登錄攔截到這里就結束了嗎? 並沒有. 這種方式只是簡單的前端路由控制, 並不能真正阻止用戶訪問需要登錄權限的路由. 還有一種情況便是: 當前 token 失效了, 但是 token 依然保存在本地. 這時候你去訪問需要登錄權限的路由時, 實際上應該讓用戶重新登錄.

這時候就需要結合 http 攔截器 + 后端接口返回的 http 狀態碼來判斷.

2. 攔截器

要想統一處理所有 http 請求和響應, 就得用上 axios 的攔截器. 通過配置 http response inteceptor, 當后端接口返回 401 Unauthorized(未授權), 讓用戶重新登錄.

  1. // http request 攔截器
  2. axios.interceptors.request.use(
  3. config =>{
  4. if(store.state.token){// 判斷是否存在 token, 如果存在的話, 則每個 http header 都加上 token
  5. config.headers.Authorization=`token ${store.state.token}`;
  6. }
  7. return config;
  8. },
  9. err =>{
  10. returnPromise.reject(err);
  11. });
  12. // http response 攔截器
  13. axios.interceptors.response.use(
  14. response =>{
  15. return response;
  16. },
  17. error =>{
  18. if(error.response){
  19. switch(error.response.status){
  20. case401:
  21. // 返回 401 清除 token 信息並跳轉到登錄頁面
  22. store.commit(types.LOGOUT);
  23. router.replace({
  24. path:'login',
  25. query:{redirect: router.currentRoute.fullPath}
  26. })
  27. }
  28. }
  29. returnPromise.reject(error.response.data)// 返回接口返回的錯誤信息
  30. });

3.2 axios 攔截器對 http 請求的響應狀態統一進行處理

首先我們要明白設置攔截器的目的是什么, 當我們需要統一處理 http 請求和響應時我們通過設置攔截器處理方便很多.

這個項目我引入了 element ui 框架, 所以我是結合 element 中 loading 和 message 組件來處理的. 我們可以單獨建立一個 http 的 js 文件處理 axios, 再到 main.js 中引入.

  1. /**
  2. * http 配置
  3. */
  4. // 引入 axios 以及 element ui 中的 loading 和 message 組件
  5. import axios from'axios'
  6. import{Loading,Message}from'element-ui'
  7. // 超時時間
  8. axios.defaults.timeout =5000
  9. // http 請求攔截器
  10. var loadinginstace
  11. axios.interceptors.request.use(config =>{
  12. // element ui Loading 方法
  13. loadinginstace =Loading.service({ fullscreen:true})
  14. return config
  15. }, error =>{
  16. loadinginstace.close()
  17. Message.error({
  18. message:'加載超時'
  19. })
  20. returnPromise.reject(error)
  21. })
  22. // http 響應攔截器
  23. axios.interceptors.response.use(data =>{// 響應成功關閉 loading
  24. loadinginstace.close()
  25. return data
  26. }, error =>{
  27. loadinginstace.close()
  28. Message.error({
  29. message:'加載失敗'
  30. })
  31. returnPromise.reject(error)
  32. })
  33. exportdefault axios

3.3 axios 攔截器對重復請求的處理

axios 官方文檔上給了兩種取消請求的方式.

輕查看: vue axios 在切換路由時如何取消所有請求 --cancelToken

根據文檔上的第二種方法, 我們可以在攔截器里統一處理取消重復請求

  1. let pending =[];// 聲明一個數組用於存儲每個 ajax 請求的取消函數和 ajax 標識
  2. let cancelToken = axios.CancelToken;
  3. let removePending =(config)=>{
  4. for(let p in pending){
  5. if(pending[p].u === config.url +'&'+ config.method){// 當當前請求在數組中存在時執行函數體
  6. pending[p].f();// 執行取消操作
  7. pending.splice(p,1);// 把這條記錄從數組中移除
  8. }
  9. }
  10. }
  11. // 添加請求攔截器
  12. axios.interceptors.request.use(config=>{
  13. removePending(config);// 在一個 ajax 發送前執行一下取消操作
  14. config.cancelToken =new cancelToken((c)=>{
  15. // 這里的 ajax 標識我是用請求地址 & 請求方式拼接的字符串, 當然你可以選擇其他的一些方式
  16. pending.push({ u: config.url +'&'+ config.method, f: c });
  17. });
  18. return config;
  19. },error =>{
  20. returnPromise.reject(error);
  21. });
  22. // 添加響應攔截器
  23. axios.interceptors.response.use(response=>{
  24. removePending(res.config);// 在一個 ajax 響應后再執行一下取消操作, 把已經完成的請求從 pending 中移除
  25. return response;
  26. },error =>{

return { data: { } }; 返回一個空對象, 主要是防止控制台報錯

});

同一個請求, 沒有完成的請求將被取消

利用這個方法, 一方面可以防止重復點擊不同頁碼導致的表格數據閃爍, 另外可以做實時搜索, 始終獲取最新結果.

最后取消重復請求會有些問題. 第二次請求時后台已經接收到了請求. 還是會生成 2 次相同的數據. 下面是對應的處理:

  1. let pending =[]
  2. letCancelToken= axios.CancelToken
  3. let removePending =(config, f)=>{
  4. let flagUrl = config.url +'&'+ config.method
  5. if(pending.indexOf(flagUrl)!==-1){
  6. if(f){
  7. f()// 執行取消操作
  8. }else{
  9. pending.splice(pending.indexOf(flagUrl),1)// 把這條記錄從數組中移除
  10. }
  11. }else{
  12. if(f){
  13. pending.push(flagUrl)
  14. }
  15. }
  16. }
  17. // http request 攔截器
  18. HTTP.interceptors.request.use(
  19. config =>{
  20. if(config.method ==='post'){
  21. console.log('我是攔截')
  22. config.cancelToken =newCancelToken((c)=>{
  23. removePending(config, c)
  24. })
  25. }
  26. return config
  27. },
  28. err =>{
  29. returnPromise.reject(err)
  30. })
  31. // http response 攔截器
  32. HTTP.interceptors.response.use(
  33. response =>{
  34. if(response.config.method ==='post'){
  35. removePending(response.config)
  36. }
  37. return response
  38. },
  39. error =>{
  40. pending =[]
  41. return{ data:{error: error}}// 返回接口返回的錯誤信息
  42. })

第一種適合 tabs, 分頁等快速來回點擊的情況, 取消之前的請求, 保持最近的一次請求.

第二種適合相同的接口被請求了多次, 只留第一次, 其他的都取消請求.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM