linche0859
10/17/2019 - 7:30 AM

axios封裝

安裝

npm i axios
## vue提示
npm i vant

準備

public資料夾下新增data.json

{
  "token": "requestToken",
  "todolist": [
    {
      "id": 1,
      "title": "Html",
      "content": "This is html",
      "status": true
    },
    {
      "id": 2,
      "title": "CSS",
      "content": "This is css",
      "status": false
    }
  ]
}

src下新增api資料夾和index.jsbase.js

檔案功能
index1.封裝 axios
2.斷網情況處理
請求和響應攔截
base接口域名有多個情況

index.js

import axios from 'axios'
import store from '@/store'
import router from '@/router'
import { Toast } from 'vant'

/**
 * 提示函数
 * 禁止點擊蒙層、顯示一秒後關閉
 */
const tip = msg => {
  Toast({
    message: msg,
    duration: 1000,
    forbidClick: true
  })
}

/**
 * 跳轉登錄頁
 * 攜帶當前頁面路由,以期在登錄頁面完成登錄後返回當前頁面
 */
const toLogin = () => {
  router.replace({
    path: '/login',
    query: {
      redirect: router.currentRoute.fullPath
    }
  })
}

/**
 * 請求失敗後的錯誤統一處理
 * @param {Number} status 請求失敗的狀態碼
 */
const errorHandle = (status, other) => {
  // 狀態碼判斷
  switch (status) {
    // 401: 未登錄狀態,跳轉登錄頁
    case 401:
      toLogin()
      break
    // 403 token過期
    // 清除token並跳轉登錄頁
    case 403:
      tip('登錄過期,請重新登錄')
      localStorage.removeItem('token')
      store.commit('loginSuccess', null)
      setTimeout(() => {
        toLogin()
      }, 1000)
      break
    // 404請求不存在
    case 404:
      tip('請求的資源不存在')
      break
    default:
      console.log(other)
  }
}

// 創建axios實例
var instance = axios.create({ timeout: 1000 * 12 })
// 設置post請求頭
instance.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded'

/**
 * 請求攔截器
 * 每次請求前,如果存在token則在請求頭中攜帶token
 * 透過瀏覽器的 Network中,在 Request Headers可觀察 Authorization
 */
instance.interceptors.request.use(
  config => {
    // 登錄流程控制中,根據本地是否存在token判斷用戶的登錄情況
    // 但是即使token存在,也有可能token是過期的,所以在每次的請求頭中攜帶token
    // 後台根據攜帶的token判斷用戶的登錄情況,並返回給我們對應的狀態碼
    // 而後我們可以在響應攔截器中,根據狀態碼進行一些統一的操作
    const token = store.state.token
    // 如果token有值,才做設定
    token && (config.headers.Authorization = token)
    return config
  },
  error => Promise.error(error)
)

// 響應攔截器
instance.interceptors.response.use(
  // 請求成功
  res => (res.status === 200 ? Promise.resolve(res) : Promise.reject(res)),
  // 請求失敗
  error => {
    const { response } = error
    if (response) {
      // 請求已發出,但是不在2xx的範圍
      errorHandle(response.status, response.data.message)
      return Promise.reject(response)
    } else {
      // 處理斷網的情況
      // eg:請求超時或斷網時,更新state的network狀態
      // network狀態在app.vue中控制著一個全局的斷網提示組件的顯示隱藏
      // 關於斷網組件中的刷新重新獲取數據,會在斷網組件中說明
      if (!window.navigator.onLine) {
        store.commit('CHANGE_NETWORK', false)
      } else {
        return Promise.reject(error)
      }
    }
  }
)

export default instance

Base.js

/**
 * 接口域名的管理
 */
const base = {
  dev: 'data.json',
  prod: 'data1.json'
}

export default base

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from '@/api' // 導入http中創建的axios實例
import base from '@/api/base' // 導入接口域名列表
import todolist from '@/store/module/todolist'

Vue.use(Vuex)

export default new Vuex.Store({
  strict: process.env.NODE_ENV !== 'production',
  state: {
    token: null,
    network: true
  },
  modules: {
    todolist
  },
  mutations: {
    GET_TOKEN(state, data) {
      state.token = data
    },
    CHANGE_NETWORK(state, val) {
      state.network = val
    }
  },
  actions: {
    // 取得 token
    getToken({ commit }) {
      axios.get(`${base.dev}`).then(res => {
        commit('GET_TOKEN', res.data.token)
      })
    }
  }
})

main.js

加上

import api from '@/api'
// 將api掛載到vue的原型上
// 目的讓各 component也能直接使用
Vue.prototype.$api = api

store/module/todolist.js

import axios from '@/api' // 導入http中創建的axios實例
import base from '@/api/base' // 導入接口域名列表

const state = {
  list: []
}

const mutations = {
  GET_TOLIST(state, data) {
    state.list = data
  }
}

const actions = {
  getTodoList({ commit }) {
    axios.get(`${base.dev}`).then(res => {
      commit('GET_TOLIST', res.data.todolist)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

about.vue

可以使用$api讀取資料,如

this.$api.get(`${base.prod}`).then(res => {
  console.log(res.data.todolist)
})

因為使用vuex模組化,使用注意為

this.$store.dispatch('todolist/getTodoList')