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 攔截器簡單介紹
- // 添加一個請求攔截器
- axios.interceptors.request.use(function(config){
- // Do something before request is sent
- return config;
- },function(error){
- // Do something with request error
- returnPromise.reject(error);
- });
- // 添加一個響應攔截器
- axios.interceptors.response.use(function(response){
- // Do something with response data
- return response;
- },function(error){
- // Do something with response error
- returnPromise.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){
- // 對請求錯誤做些什么
- returnPromise.reject(error)
- });
- // 添加響應攔截器
- axios.interceptors.response.use(function(response){
- // 對響應數據做點什么
- return response
- },function(error){
- // 對響應錯誤做點什么
- returnPromise.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 =>{
- returnPromise.reject(err);
- });
- // http response 攔截器
- axios.interceptors.response.use(
- response =>{
- return response;
- },
- error =>{
- if(error.response){
- switch(error.response.status){
- case401:
- // 返回 401 清除 token 信息並跳轉到登錄頁面
- store.commit(types.LOGOUT);
- router.replace({
- path:'login',
- query:{redirect: router.currentRoute.fullPath}
- })
- }
- }
- returnPromise.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:'加載超時'
- })
- returnPromise.reject(error)
- })
- // http 響應攔截器
- axios.interceptors.response.use(data =>{// 響應成功關閉 loading
- loadinginstace.close()
- return data
- }, error =>{
- loadinginstace.close()
- Message.error({
- message:'加載失敗'
- })
- returnPromise.reject(error)
- })
- exportdefault 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 =>{
- returnPromise.reject(error);
- });
- // 添加響應攔截器
- axios.interceptors.response.use(response=>{
- removePending(res.config);// 在一個 ajax 響應后再執行一下取消操作, 把已經完成的請求從 pending 中移除
- return response;
- },error =>{
return { data: { } }; 返回一個空對象, 主要是防止控制台報錯
});
同一個請求, 沒有完成的請求將被取消
利用這個方法, 一方面可以防止重復點擊不同頁碼導致的表格數據閃爍, 另外可以做實時搜索, 始終獲取最新結果.
最后取消重復請求會有些問題. 第二次請求時后台已經接收到了請求. 還是會生成 2 次相同的數據. 下面是對應的處理:
- let pending =[]
- letCancelToken= 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 =newCancelToken((c)=>{
- removePending(config, c)
- })
- }
- return config
- },
- err =>{
- returnPromise.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, 分頁等快速來回點擊的情況, 取消之前的請求, 保持最近的一次請求.
第二種適合相同的接口被請求了多次, 只留第一次, 其他的都取消請求.