VUE中對axios的封裝

前言

在VUE項目中進行數據交互使用的比較多的就是axios,新手一般都是安裝完axios插件後在需要的地方直接使用axios.get()或axios.post(),我也不例外。在小項目中的確這種方式簡單快捷,但是當在大項目中還是這樣使用起來就顯得非常的繁瑣,自己也開始研究如何進行優化,把公共的部分提取出來,減少代碼的沉餘。但是始終還是覺得自己的想法不夠先進,後面在看一個VUE開源項目的時候發現它對axios進行封裝的很好,於是借鑑了一下。

目錄結構

在src目錄下新建文件夾api,api文件夾下新建apis文件夾(存放所有api接口)、urls文件夾(存放所有api接口的url)、axios文件(對axios進行配置)、index.js文件。

axios.js(配置【完整全部內容見最後】)

1.對請求頭部進行配置(基礎的url、請求超時、headers)

const tokenKey = 'JEECMS-Auth-Token'
const request = axios.create({
  baseURL: process.env.VUE_APP_API_PREFIX,
  timeout: 50000,
  headers: {
    'Content-Type': 'application/json',
    'Redirect-Header': false
  }
})

2.對請求參數進行配置

const baseHeader = () => {  //動態獲取token和標誌性的ID
  const token = window.localStorage.getItem(tokenKey)
  const siteId = window.localStorage.getItem('siteId')
  return {   //返回新的內容
    [tokenKey]: token,
    siteId
  }
}
request.interceptors.request.use(config => {
  config.headers = Object.assign({}, baseHeader(), config.headers)   //修改headers
  if (!config.url) {   //使用elementUI的消息框進行提示
    Message.error({
      showClose: true,
      message: '接口地址錯誤',
      type: 'error',
      duration: 3 * 1000
    })
  } else if (config.url.endsWith('/admin/login')) {   //特殊情況處理
    config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    config.data = qs.stringify(config.data)
  }
  return config
}, error => {   //對請求出錯後的處理
  console.log(error)
  return Promise.reject(error)
})

3.對返回參數進行配置

request.interceptors.response.use(response => {
  if (response.data.token && response.data.token !== '') {
    localStorage.setItem(tokenKey, response.data.token)
  }
  return response
}, error => {
  // console.log(error)
  let message = error.message
  if (error.response.status === 404) {
    message = '接口訪問失敗'
  }
  Message({
    showClose: true,
    message,
    type: 'error',
    duration: 3 * 1000
  })
  return Promise.reject(error)
})

4.對請求結果狀態處理

const checkStatus = response => {
  if (response && response.status === 401) {
    window.localStorage.setItem(tokenKey, '')
    const url = window.location.hash.substr(1)
    if (/^\/login/.test(url)) {
      router.push(url)
    } else {
      router.push(`/login?redirect=${escape(url)}`)
    }
    return
  }
  if (response && (response.status === 200 || response.status === 304 || response.status === 400 || response.status === 404)) {
    return response.data
  }
  return {
    status: -404,
    msg: '網絡異常'
  }
}

function checkCode (res) {
  if ([501, 502, 503, 506].includes(res.code)) {
    window.localStorage.setItem(tokenKey, '')
    const url = window.location.hash.substr(1)
    if (/^\/login/.test(url)) {
      router.push(url)
    } else {
      router.push(`/login?redirect=${escape(url)}`)
    }
  }
  if (res.code !== 200) {
    Message({
      showClose: true,
      message: res.message || '服務器端錯誤',
      type: 'error',
      duration: 3 * 1000
    })
  }
  return res
}

 5.導出各種請求方式

export default {
  request (config) {
    return axios.request(config).then(checkStatus).then(checkCode)
  },
  login (url, data) {
    return requestLogin({
      method: 'post',
      url,
      data
    }).then(checkStatus).then(checkCode)
  },
  upload (url, data, onUploadProgress = () => {}) {
    return request({
      method: 'post',
      url,
      headers: { 'Content-Type': 'multipart/form-data' },
      data,
      onUploadProgress
    }).then(checkStatus).then(checkCode)
  },
  download (url, data, onDownloadProgress = () => {}) {
    return request({
      method: 'post',
      url,
      data,
      responseType: 'blob',
      onDownloadProgress
    }).then(checkStatus)
  },
  post (url, data, onUploadProgress = () => {}) {
    return request({
      method: 'post',
      url,
      data,
      onUploadProgress
    }).then(checkStatus).then(checkCode)
  },
  get (url, params, headers = {}) {
    return request({
      method: 'get',
      url,
      params,
      headers
    }).then(checkStatus).then(checkCode)
  },
  put (url, data) {
    return request({
      method: 'put',
      url,
      data
    }).then(checkStatus).then(checkCode)
  },
  patch (url, data) {
    return request({
      method: 'patch',
      url,
      data
    }).then(checkStatus).then(checkCode)
  },
  delete (url, data) {
    return request({
      method: 'delete',
      url,
      data
    }).then(checkStatus).then(checkCode)
  }
}

URL封裝(以登陸模塊爲例)

const prefix = '/admin'

export default {
  // 驗證碼
  code: '/common/kaptcha',
  // 登陸
  login: `${prefix}/login`,
  // 上傳
  upload: `${prefix}/upload/o_upload`,
  // 返回中文首字母
  pinyin: '/language/pinyin',
  // 自動摘要
  summary: '/language/summary',
  // 修改密碼
  adminpsw: `${prefix}/users/adminpsw`,
  // 導入word
  docImport: `${prefix}/contentext/docImport`
}

接口封裝(以登陸模塊爲例)

import axios from '../axios'
import loginUrls from '../urls/login'

export default {
  fetchCode () {
    return axios.get(loginUrls.code)
  },
  fetchLogin (data) {
    return axios.login(loginUrls.login, data)
  },
  fetchUpload (data, onUploadProgress) {
    return axios.upload(loginUrls.upload, data, onUploadProgress)
  },
  fetchPinyin (data) {
    return axios.get(loginUrls.pinyin, data)
  },
  fetchSummary (data) {
    return axios.post(loginUrls.summary, data)
  },
  fetchAdminPsw (data) {
    return axios.post(loginUrls.adminpsw, data)
  },
  fetchDocImport (data) {
    return axios.upload(loginUrls.docImport, data)
  }
}

index.js

const modulesFiles = require.context('./apis', true, /\.js$/)
// 這裏是webpack的方法,參數說明:要搜索的文件夾目錄、是否還應該搜索它的子目錄、以及一個匹配文件的正則表達式
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  const value = modulesFiles(modulePath)
  modules = Object.assign(modules, value.default)
  return modules
}, {})

export default modules

如何使用

在需要的地方使用如下方法調用接口

this.fetchLogin(data).then(res => {.....})

給自己做個宣傳

本人個人博客:www.dzyong.com

 

附錄:axios.js全部內容

import axios from 'axios'
import qs from 'qs'
import { Message } from 'element-ui'
import router from '@/routes'

const tokenKey = 'JEECMS-Auth-Token'
const request = axios.create({
  baseURL: process.env.VUE_APP_API_PREFIX,
  timeout: 50000,
  headers: {
    'Content-Type': 'application/json',
    'Redirect-Header': false
  }
})

const baseHeader = () => {
  const token = window.localStorage.getItem(tokenKey)
  const siteId = window.localStorage.getItem('siteId')
  return {
    [tokenKey]: token,
    siteId
  }
}

request.interceptors.request.use(config => {
  config.headers = Object.assign({}, baseHeader(), config.headers)
  if (!config.url) {
    Message.error({
      showClose: true,
      message: '接口地址錯誤',
      type: 'error',
      duration: 3 * 1000
    })
  } else if (config.url.endsWith('/admin/login')) {
    config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    config.data = qs.stringify(config.data)
  }
  return config
}, error => {
  console.log(error)
  return Promise.reject(error)
})

request.interceptors.response.use(response => {
  if (response.data.token && response.data.token !== '') {
    localStorage.setItem(tokenKey, response.data.token)
  }
  return response
}, error => {
  // console.log(error)
  let message = error.message
  if (error.response.status === 404) {
    message = '接口訪問失敗'
  }
  Message({
    showClose: true,
    message,
    type: 'error',
    duration: 3 * 1000
  })
  return Promise.reject(error)
})

const checkStatus = response => {
  if (response && response.status === 401) {
    window.localStorage.setItem(tokenKey, '')
    const url = window.location.hash.substr(1)
    if (/^\/login/.test(url)) {
      router.push(url)
    } else {
      router.push(`/login?redirect=${escape(url)}`)
    }
    return
  }
  if (response && (response.status === 200 || response.status === 304 || response.status === 400 || response.status === 404)) {
    return response.data
  }
  return {
    status: -404,
    msg: '網絡異常'
  }
}

function checkCode (res) {
  if ([501, 502, 503, 506].includes(res.code)) {
    window.localStorage.setItem(tokenKey, '')
    const url = window.location.hash.substr(1)
    if (/^\/login/.test(url)) {
      router.push(url)
    } else {
      router.push(`/login?redirect=${escape(url)}`)
    }
  }
  if (res.code !== 200) {
    Message({
      showClose: true,
      message: res.message || '服務器端錯誤',
      type: 'error',
      duration: 3 * 1000
    })
  }
  return res
}

// 登錄用的請求實例
const requestLogin = axios.create({
  baseURL: process.env.VUE_APP_API_PREFIX,
  timeout: 50000,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
})

requestLogin.interceptors.request.use(config => {
  config.data = qs.stringify(config.data)
  return config
}, error => {
  return Promise.reject(error)
})

requestLogin.interceptors.response.use(response => {
  return response
}, error => {
  let message = error.message
  if (error.response.status === 404) {
    message = '接口訪問失敗'
  }
  Message({
    showClose: true,
    message,
    type: 'error',
    duration: 3 * 1000
  })
  return Promise.reject(error)
})

export default {
  request (config) {
    return axios.request(config).then(checkStatus).then(checkCode)
  },
  login (url, data) {
    return requestLogin({
      method: 'post',
      url,
      data
    }).then(checkStatus).then(checkCode)
  },
  upload (url, data, onUploadProgress = () => {}) {
    return request({
      method: 'post',
      url,
      headers: { 'Content-Type': 'multipart/form-data' },
      data,
      onUploadProgress
    }).then(checkStatus).then(checkCode)
  },
  download (url, data, onDownloadProgress = () => {}) {
    return request({
      method: 'post',
      url,
      data,
      responseType: 'blob',
      onDownloadProgress
    }).then(checkStatus)
  },
  post (url, data, onUploadProgress = () => {}) {
    return request({
      method: 'post',
      url,
      data,
      onUploadProgress
    }).then(checkStatus).then(checkCode)
  },
  get (url, params, headers = {}) {
    return request({
      method: 'get',
      url,
      params,
      headers
    }).then(checkStatus).then(checkCode)
  },
  put (url, data) {
    return request({
      method: 'put',
      url,
      data
    }).then(checkStatus).then(checkCode)
  },
  patch (url, data) {
    return request({
      method: 'patch',
      url,
      data
    }).then(checkStatus).then(checkCode)
  },
  delete (url, data) {
    return request({
      method: 'delete',
      url,
      data
    }).then(checkStatus).then(checkCode)
  }
}

 

發佈了65 篇原創文章 · 獲贊 65 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章