Vue中統一封裝Axios請求

1.Axios 是什麼,爲何要統一封裝?

axios是一個基於promise的http庫,可運行在瀏覽器端和node.js中。他有不少優秀的特性,例如統一進行攔截請求和響應、取消請求、轉換json、客戶端防護XSRF等。因此在平常開發中能夠直接推薦咱們使用axios庫。若是還對axios不瞭解的,能夠移步axios文檔。迴歸正題,咱們所要的說的axios的封裝和api接口的統一管理,其實主要目的就是在幫助咱們簡化代碼和利於後期的更新維護。
node

2.統一封裝攔截器和get/post請求

import axios from 'axios'    
import { Loading, Message } from 'element-ui'    // 這裏我是使用elementUI的組件來給提示
import router from '@/router'

let loadingInstance = null     // 加載全局的loading

const instance = axios.create({    //建立axios實例,在這裏能夠設置請求的默認配置
  timeout: 10000, // 設置超時時間10s
  baseURL: process.env.NODE_ENV === 'production' ? '' : '/api'   //根據本身配置的反向代理去設置不一樣環境的baeUrl
})
// 文檔中的統一設置post請求頭。下面會說到post請求的幾種'Content-Type'
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

let httpCode = {        //這裏我簡單列出一些常見的http狀態碼信息,能夠本身去調整配置
  400: '請求參數錯誤',
  401: '權限不足, 請從新登陸',
  403: '服務器拒絕本次訪問',
  404: '請求資源未找到',
  500: '內部服務器錯誤',
  501: '服務器不支持該請求中使用的方法',
  502: '網關錯誤',
  504: '網關超時'
}

/** 添加請求攔截器 **/
instance.interceptors.request.use(config => {
  config.headers['token'] = sessionStorage.getItem('token') || ''
  loadingInstance = Loading.service({       // 發起請求時加載全局loading,請求失敗或有響應時會關閉
    spinner: 'fa fa-spinner fa-spin fa-3x fa-fw',
    text: '拼命加載中...'
  })
  if (config.method === 'get') { // 添加時間戳參數,防止瀏覽器(IE)對get請求的緩存
    config.params = {
      ...config.params,
      t: new Date().getTime()
    }
  }
  // 在這裏:能夠根據業務需求能夠在發送請求以前作些什麼:例如我這個是導出文件的接口,由於返回的是二進制流,因此須要設置請求響應類型爲blob,就能夠在此處設置。
  if (config.url.includes('pur/contract/export')) {
    config.headers['responseType'] = 'blob'
  }
  // 我這裏是文件上傳,發送的是二進制流,因此須要設置請求頭的'Content-Type'
  if (config.url.includes('pur/contract/upload')) {
    config.headers['Content-Type'] = 'multipart/form-data'
  }
  return config
}, error=> {
  // 對請求錯誤作些什麼
  return Promise.reject(error)
})

/** 添加響應攔截器  **/
instance.interceptors.response.use(response => {
  loadingInstance.close()
  if (response.data.status === 'ok') {     // 響應結果裏的status: ok是我與後臺的約定,你們能夠根據實際狀況去作對應的判斷
    return Promise.resolve(response.data)
  } else {
    Message({
      message: response.data.message,
      type: 'error'
    })
    return Promise.reject(response.data.message)
  }
}, error => {
  loadingInstance.close()
  if (error.response) {     
        // 根據請求失敗的http狀態碼去給用戶相應的提示
    let tips = error.response.status in httpCode ? httpCode[error.response.status] : error.response.data.message
    Message({
      message: tips,
      type: 'error'
    })
    if (error.response.status === 401) {    // token或者登錄失效狀況下跳轉到登陸頁面,根據實際狀況,在這裏能夠根據不一樣的響應錯誤結果,作對應的事。這裏我以401判斷爲例
      router.push({
        path: `/login`
      })
    }
    return Promise.reject(error)
  } else {
    Message({
      message: '請求超時, 請刷新重試',
      type: 'error'
    })
    return Promise.reject(new Error('請求超時, 請刷新重試'))
  }
})

/* 統一封裝get請求 */
export const get = (url, params, config = {}) => {
  return new Promise((resolve, reject) => {
    instance({
      method: 'get',
      url,
      params,
      ...config
    }).then(response => {
      resolve(response)
    }).catch(error => {
      reject(error)
    })
  })
}

/* 統一封裝post請求  */
export const post = (url, data, config = {}) => {
  return new Promise((resolve, reject) => {
    instance({
      method: 'post',
      url,
      data,
      ...config
    }).then(response => {
      resolve(response)
    }).catch(error => {
      reject(error)
    })
  })
}

/* 或者寫成下面這樣: Promise.resolve() 和 Promise.reject()返回的是promise對象,兩者都是語法糖  */
export const post = (url, data, config = {}) => {
  return instance({
    method: 'post',
    url,
    data,
    ...config
  }).then(response => {
    return Promise.resolve(response)
  }).catch(error => {
    return Promise.reject(error)
  })複製代碼

下面幾張圖是攔截器的回調函數的一些參數:ios

  • 請求攔截器中的config


  • 響應攔截器中的response


  • 響應攔截器中的error


3.統一進行接口api管理

// 每一個模塊都應該有本身的接口文件去統一管理api
import { get, post } from '@/utils/request'

export const query = (params) => get('/pur/pay/pageInit', params)複製代碼

4.頁面上的使用

import { query } from '@/api/index'

export default {
  name: 'App',
  data () {
    return {}
  },
  mounted () {
    let params = { userName: 'admin', password: '123456'}
    query(params).then(res => {
      console.log(res, '這是響應的結果')
    })
  }
}複製代碼

5.問題梳理

  • 如何根據不一樣的接口去設置不一樣的請求頭信息,而且有怎樣的優先級順序呢?

能夠在請求的攔截器裏面config,去判斷,分別設置。也可使用已經封裝的get/post請求裏寫,在調用api時,傳第三個參數就是config的信息。配置的優先順序:配置會以一個優先順序進行合併,  這個順序是:在 lib/defaults.js 找到的庫的默認值,而後是實例的 defaults 屬性,最後是請求的 config 參數。後者將優先於前者。element-ui

  • 爲何只封裝了get和post請求?

通常狀況下axios只須要封裝post、get請求,這也是不少公司的代碼規範,至於爲何不使用其餘的請求方式,put(往服務器上傳文件),delect(刪除)直接對數據進行操做相對來講不安全 。json

  • 爲何引入axios插件不用Vue.use()

axios雖然是一個插件,可是咱們不須要經過Vue.use(axios)來使用,下載完成後,只需在項目中引入便可,若是使用Vue.use()方法的話,則該方法默認會調用install方法,然鵝axios的做者彷佛並無寫install的方法。Vue引入的組件類型必須爲Function或者是Object。  若是是個對象,必須提供install方法,須要用Vue.use(), 若是是一個函數,會被直接看成install函數執行 axios

  • 說一說post請求常見的數據格式(Content-Type)

1.application/json : 參數會直接放在請求體中,以JSON格式的發送到後端。這也是axios請求的默認方式。這種類型使用最爲普遍。


2.application/x-www-form-urlencoded:請求體中的數據會以普通表單形式(鍵值對)發送到後端。

3.multipart/form-data 參數會在請求體中,以標籤爲單元,用分隔符(能夠自定義的boundary)分開。既能夠上傳鍵值對,也能夠上傳文件。一般被用來上傳文件的格式。


最後:個人文章會持續更新完善中···, 若是文章對您有幫助,請點贊^_^,或者留言交流~~
後端

相關文章
相關標籤/搜索