vue axios封裝之取消請求

在最美好的年華,沒有遇到愛情,只遇到了疫情

應用環境,當咱們項目中使用模糊匹配查詢列表的時候,輸入框中輸入關鍵字,咱們就會根據關鍵字調接口查詢數據,若是輸入的很快,接口反應不是很快,那麼就會出現搜索出來的數據和輸入的關鍵字不匹配的狀況。這時候咱們就須要配置axios請求的CancelToken來取消尚未響應完的接口,直接根據最新輸入查詢接口,匹配最新的結果
image.pngphp

引入axios定義須要的變量

// 引入axios
import axios from 'axios'
...
let cancel
let promiseArr = {}
const CancelToken = axios.CancelToken

在請求攔截器中配置

// 取消請求
  if (promiseArr[config.url]) {
    promiseArr[config.url]('操做取消')
    promiseArr[config.url] = cancel
  } else {
    promiseArr[config.url] = cancel
  }

在get/post/put請求中配置

...
axios.get(url, {
      params: params,
      cancelToken: new CancelToken(c => {
        cancel = c
      })
    }).then(res => {
    ...
axios.post(
      url,
      params,
      {
        cancelToken: new CancelToken(c => {
          cancel = c
        })
      }
    ).then(res => {

vue中axios封裝完整代碼

// 引入axios
import axios from 'axios'
// 引入qs模塊,用來序列化post類型的數據,後面會提到
// import QS from 'qs'
import store from '@/store/index'
import router from '@/router/index'
// elementUi提示組件。
import { Message } from 'element-ui'
// import {LoadingBar} from 'iview'
let cancel
let promiseArr = {}
const CancelToken = axios.CancelToken
// 環境的切換
console.log(process.env.NODE_ENV, process.env.ENV_CONFIG, '環境參數')
if (process.env.NODE_ENV === 'development') {
  console.log(router, store, 'http.js中的路由器信息')
  axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate'
} else if (process.env.NODE_ENV === 'testing') {
  axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate'
} else if (process.env.NODE_ENV === 'production') {
  axios.defaults.baseURL = 'https://www.bangying.tech/api'
}
// 設置請求最大時長
axios.defaults.timeout = 50000
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
axios.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'
axios.defaults.headers.common['By-User-Info'] = localStorage.getItem('userInfo_admin') ? JSON.parse(localStorage.getItem('userInfo_admin')).user_id : ''
axios.defaults.withCredentials = true
// 請求攔截器
axios.interceptors.request.use(config => {
  // 若是不是登陸接口,或者微信分享接口,都須要驗證token, 隱私策略
  // if (window.location.hash.indexOf('login') === -1 && window.location.hash.indexOf('wechat-share') === -1 && window.location.hash.indexOf('private') === -1) {
  //   const token = store.state.userInfo.Authorization
  //   token && (config.headers.Authorization = token)
  // }
  // 取消請求
  if (promiseArr[config.url]) {
    promiseArr[config.url]('操做取消')
    promiseArr[config.url] = cancel
  } else {
    promiseArr[config.url] = cancel
  }
  // 配置request請求頭header中的Authorization,若是登錄了就有Authorization就設置一下
  if (store.state.userInfo && store.state.userInfo.Authorization) {
    const token = store.state.userInfo.Authorization
    token && (config.headers.Authorization = token)
  }
  return config
}, error => {
  Message.error({
    message: '請求接口出錯',
    duration: 3000
  })
  return Promise.error(error)
})

// 響應攔截器
axios.interceptors.response.use(response => {
  // 若是返回的狀態碼爲200,說明接口請求成功,能夠正常拿到數據
  // 不然的話拋出錯誤
  if (response.status === 200) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(response)
  }
}, error => {
  if (error.response.status) {
    switch (error.response.status) {
      // 401: 未登陸
      // 未登陸則跳轉登陸頁面,並攜帶當前頁面的路徑
      // 在登陸成功後返回當前頁面,這一步須要在登陸頁操做。
      case 401:
        // Message.error({
        //   message: '無權限',
        //   duration: 1000
        // })
        // window.location.href = store.getters.base_url + 'new-home/#/login'
        // router.replace({name: 'login'})
        break
      // 403 token過時
      // 登陸過時對用戶進行提示
      // 清除本地token和清空vuex中token對象
      // 跳轉登陸頁面
      case 403:
        // Message.error({
        //   message: '登陸過時,請從新登陸',
        //   duration: 1000
        // })
        // 清除token
        // localStorage.removeItem('token')
        // store.commit('loginSuccess', null)
        // 跳轉登陸頁面,並將要瀏覽的頁面fullPath傳過去,登陸成功後跳轉須要訪問的頁面
        // window.location.href = store.getters.base_url + 'new-home/#/login'
        localStorage.clear()
        store.dispatch('loginOut')
        break
        // 404請求不存在
      case 404:
        Message.error({
          message: '網絡請求不存在',
          duration: 1500
        })
        break
      // 其餘錯誤,直接拋出錯誤提示
      default: {
        // Message.error({
        //   message: error.response.data.message,
        //   duration: 1500
        // })
      }
    }
    return Promise.reject(error.response)
  }
})

export function get (url, params, config) {
  if (config) {
    axios.defaults.headers.post['Content-Type'] = 'multipart/form-data'
  }
  // LoadingBar.start()
  let phpApi = false
  // get方法中使用php接口地址
  if (
    url === '/index.php/file/upload_token' ||
    url === '/index.php/home_page/currency' ||
    url === '/index.php/count_channel/channel_province_count' ||
    url === '/index.php/count_channel/channel_history_count' ||
    url === '/index.php/count_channel/channel_role_count' ||
    url === '/index.php/count_channel/channel_newadd_count' ||
    url === '/index.php/count_project/project_num_count' ||
    url === '/index.php/count_project/department_count' ||
    url === '/index.php/count_project/project_count_total' ||
    url === '/index.php/user/department' ||
    url === '/index.php/count_project/project_department_num_count' ||
    url === '/index.php/count_project/province_count' ||
    url === '/index.php/count_project/clue_source_count' ||
    url === '/index.php/count_project/stage_count' ||
    url === '/index.php/count_project/reason_count' ||
    url === '/index.php/count_project/project_time_count' ||
    url === '/index.php/count_project/project_time_department_count' ||
    url === '/index.php/count_project/duban_money_count' ||
    url === '/index.php/count_project/refuse_count' ||
    url === '/index.php/count_project/project_evaltime_count' ||
    url === '/index.php/count_project/accept_count'
  ) {
    phpApi = true
  } else {
    phpApi = false
  }

  // 線上環境
  if (process.env.NODE_ENV === 'production') {
    // 上傳token
    if (phpApi) {
      axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
    } else {
      axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
    }
  } else {
    // 開發測試環境
    // 獲取上傳token
    if (phpApi) {
      axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
    } else {
      axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
    }
  }
  return new Promise(async (resolve, reject) => {
    await axios.get(url, {
      params: params,
      cancelToken: new CancelToken(c => {
        cancel = c
      })
    }).then(res => {
      resolve(res.data)
      // LoadingBar.finish()
    }).catch(err => {
      reject(err.data)
      // LoadingBar.error()
    })
  })
}
export function post (url, params, config) {
  if (config) {
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
  }
  // LoadingBar.start()
  console.log(window.location.hash)
  return new Promise((resolve, reject) => {
    // 線上環境
    if (process.env.NODE_ENV === 'production') {
      // php接口
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/login/wechat' ||
        url === '/index.php/login/un_login'

      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
      } else if (url === 'qiniu') {
        axios.defaults.baseURL = ''
        url = 'https://qiniu.pangu.tech/'
      } else {
        // java接口
        axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
      }
    } else {
      // 開發測試環境
      // 若是是php接口
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/login/wechat' ||
        url === '/index.php/login/un_login'
      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
      } else if (url === 'qiniu') {
        axios.defaults.baseURL = ''
        url = 'https://qiniu.pangu.tech/'
      } else {
        // java接口
        axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
      }
    }
    axios.post(
      url,
      params,
      {
        cancelToken: new CancelToken(c => {
          cancel = c
        })
      }
    ).then(res => {
      resolve(res.data)
      // LoadingBar.finish()
    }).catch(err => {
      reject(err.data)
      // LoadingBar.error()
    })
  })
}

export function put (url, params) {
  // LoadingBar.start()
  console.log(window.location.hash)
  return new Promise((resolve, reject) => {
    // 線上環境
    if (process.env.NODE_ENV === 'production') {
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/project/up_status'
      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
      } else if (url === 'qiniu') {
        axios.defaults.baseURL = ''
        url = 'https://qiniu.pangu.tech/'
      } else {
        axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
      }
    } else {
      // 開發測試環境
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/project/up_status'
      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
      } else {
        axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
      }
    }
    axios.put(
      url,
      params,
      {
        cancelToken: new CancelToken(c => {
          cancel = c
        })
      }
    ).then(res => {
      resolve(res.data)
      // LoadingBar.finish()
    }).catch(err => {
      reject(err.data)
      // LoadingBar.error()
    })
  })
}

export function getAxios () {
  // 線上環境
  if (process.env.NODE_ENV === 'production') {
    axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
  } else {
    // 開發測試環境
    axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
  }
  return axios
}

實踐證實這樣封裝是有問題的

哭成淚人表情包|鬥圖網

下面展現真正的技術

// 引入axios
import axios from 'axios'

...

// 聲明一個數組用於存儲每一個請求的取消函數和axios標識
let pending = []
const CancelToken = axios.CancelToken
let removePending = (config) => {
  for (let p in pending) {
    if (pending[p].u === config.url + JSON.stringify(config.data) + '&' + config.method) {
      pending[p].f()
      pending.splice(p, 1)
    }
  }
}

...

// 請求攔截器
axios.interceptors.request.use(config => {
// 取消請求
  removePending(config)
  config.cancelToken = new CancelToken((c) => {
    // 這裏的axios標識我是用請求地址&請求方式拼接的字符串,固然你能夠選擇其餘的一些方式
    pending.push({ u: config.url + JSON.stringify(config.data) + '&' + config.method, f: c })
  })
  
  ...
  
})

...


// 響應攔截器
axios.interceptors.response.use(response => {

  ...
  // 取消響應
  removePending(response.config)
  
  ...
  
})

這樣在請求和響應中攔截就能夠了vue

相關文章
相關標籤/搜索