axios在企業級vue項目中的應用(附帶axios正確打開方式)

在一個大型的vue項目中,需要編寫請求接口實在太多太多了,如果每一個接口都從創建實例開始,那代碼將會相當龐大以及十分臃腫,後期很難維護,那我們來看看企業級項目中,http請求是怎麼抽離出來的吧。

在這裏插入圖片描述
首先是request.js,這個文件是用來處理axios的配置、設置攔截器等等,它創建了一個實例,並將這個實例導出。代碼如下,註釋都寫在裏面啦

import Vue from 'vue'
import axios from 'axios'
// 創建 axios 實例
const service = axios.create({
  baseURL: '/user', // 基礎地址
  timeout: 6000 // 請求超時時間
})

/**
 * 請求攔截器,攜帶每個請求的token(可選) 
 */
service.interceptors.request.use(config => {
  const token = Vue.ls.get("ACCESS_TOKEN") //token是放在vuex中的state中
  if (token) {
    config.headers['X-Access-Token'] = token // 讓每個請求攜帶自定義 token 請根據實際情況自行修改
  }
  if (config.method == 'get') {
    config.params = {
      _t: Date.parse(new Date()) / 1000, //讓每個請求都攜帶一個不同的時間參數,防止瀏覽器緩存不發送請求
      ...config.params
    }
  }
  return config
}, (error) => {
  return Promise.reject(error)
})

/**
 * 響應攔截器中的error錯誤處理
 */
const err = (error) => {
  if (error.response) {
    switch (error.response.status) {
      case 401:
        console.log({
          message: '系統提示',
          description: '未授權,請重新登錄',
          duration: 4
        })
        break
      case 403:
        console.log({
          message: '系統提示',
          description: '拒絕訪問'
        })
        break

      case 404:
        console.log({
          message: '系統提示',
          description: '很抱歉,資源未找到!',
          duration: 4
        })
        break
      case 500:
        console.log({
          message: '系統提示',
          description: 'Token失效,請重新登錄!'
        })
        break
      case 504:
        console.log({
          message: '系統提示',
          description: '網絡超時'
        })
        break
      default:
        console.log({
          message: '系統提示',
          description: error.response.data.message,
        })
        break
    }
  }
  return Promise.reject(error)
};

/**
 * 響應攔截器,將響應中的token取出,放到state中
 */
service.interceptors.response.use((response) => {
  const token = response.headers["authorization"]
  if (token) {
    Vue.ls.set("ACCESS_TOKEN", token) //token是放在vuex中的state中
  }
  return response.data
}, err)

export {
  service as axios
}

第二個便是manage.js,這個文件主要是書寫不同的http請求,getpost等,在請求中配置某些特殊的配置

import { axios } from './request'

//get
export function getAction(url,params) {
  return axios({
    url: url,
    method: 'get',
    params: params
  })
}
//post
export function postAction(url,data) {
  return axios({
    url: url,
    method:'post' ,
    data: data
  })
}

//put
export function putAction(url,data) {
  return axios({
    url: url,
    method:'put',
    data: data
  })
}

//deleteAction
export function deleteAction(url,params) {
  return axios({
    url: url,
    method: 'delete',
    params: params
  })
}

/**
 * 下載文件
 * @param {*} url: 請求地址
 * @param {*} params: 請求參數
 */
export function downFileAction(url,params){
  return axios({
    url: url,
    params: params,
    method:'get' ,
    responseType: 'blob'
  })
}
/**
 * 用於上傳文件
 * @param {*} url:請求地址
 * @param {*} data:請求體數據
 */
export function fileUploadAction(url,data){
  return axios({
    url: url,
    data: data,
    method:'post' ,
    headers:{
      'Content-Type':'multipart/form-data'
    },
    timeout:1000*60*4  //上傳時間4分鐘
  })
}

最後這個api.js文件就是我們需要寫的接口了,把接口都寫在一個文件中,也是爲了方便我們維護,在使用的時候,導入使用便可

import { getAction,deleteAction,putAction,postAction,downFileAction,fileUploadAction} from '@/api/manage'

const getTest = (params)=>getAction("/api/user/get",params);
const deleteActionTest = (params)=>deleteAction("/api/user/delete",params);
const putActionTest = (params)=>putAction("/api/user/put",params);
const postActionTest = (params)=>postAction("/api/user/post",params);
const downFileActionTest = (params)=>downFileAction("/api/user/downfile",params);
const fileUploadActionTest = (params)=>fileUploadAction("/api/user/fileupload",params);


export {
  getTest,
  deleteActionTest,
  putActionTest,
  postActionTest,
  downFileActionTest,
  fileUploadActionTest
}

附帶一個項目中用到的文件下載鏈接處理

axios.get("/api/excel",{id:'001'}).then(res=>{//返回的數據是二進制文件流
    var blob = new Blob([res],{type: 'application/force-download;charset=utf-8'});
    var downloadElement = document.createElement('a');
    var href = window.URL.createObjectURL(blob); //創建下載的鏈接
    downloadElement.href = href;
    downloadElement.download = 'name.xls'; //下載後文件名
    document.body.appendChild(downloadElement);
    downloadElement.click(); //點擊下載
    document.body.removeChild(downloadElement); //下載完成移除元素
    window.URL.revokeObjectURL(href); //釋放掉blob對象 
  })

axios的正確打開方式

axios是一個基於promise的HTTP庫,目前已經被主流瀏覽器其支持(Chrome、Firefox、Safari、Opera、Edge、IE8+)

我們先來舉個例子:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
    {{ name }}
</div>
<script>
    const vm = new Vue({
        el: "#app",
        data: {
            name: "monk"
        },
        created() {
            axios("https://xxxx").then(res=>{
                console.log(res)
            })
        }
    })
</script>

從這個例子就可以看出來,axios的使用非常簡單,我們首先需要引入axios,然後直接使用就可以了,axios有兩種寫法(2個API),一個是例子所示:axios(url, [config]),另一個是:axios(config)config是一個配置對象。我在下面會介紹如何引入和如何配置axios

引入方式可以使用cnd引入

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

也可以使用npm下載後使用

$ npm install axios
import axios from 'axios'

使用axios

我們使用axios,我總結了三種方式

1、簡單粗暴直接使用axios

axios("https://xxxx",{
    method:"get"
}).then(res=>{
    console.log(res)
})

2、使用axios請求方法的別名,在使用別名方法時 urlmethoddata 這些屬性都不必在配置中指定。

axios.get("https://xxxx").then(res=>{
    console.log(res)
})
//這裏所有的請求方法都有別名
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])

3、創建axios實例,實例上的方法和請求別名相同

const service = axios.create()
service.get("https://monk/api/getUserInfo").then(res=>{
    console.log(res)
})

axios配置

我再簡單列舉一下axios常用的配置

{
  url: "", // 用於請求的服務器的地址
  method: 'get', // 請求時使用的方法,默認是 get
  baseURL: 'https://monk/api/', //baseURL將自動加在url前面
  headers: {},//定義請求頭的信息
  params: {}, // 將與請求一起發送的 URL 參數,會拼接在url後面
  data: {},  //會將請求參數放在請求體中
  timeout: 1000, //請求超時的毫秒數,超出時間後,請求就會被中斷
  responseType: 'json', // 默認是json,表示服務器響應的數據類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
}

在對axios進行配置時可以從三個方面進行配置,全局上配置,實例上配置,請求上配置,他們也是有優先級的,請求配置>實例配置>全局配置,我來依次介紹一下:

  • 全局配置:但是我們在實際的項目中,很少使用全局配置
axios.defaults.baseURL = 'https://www.monk.com/api';
axios.defaults.timeout = 1000;
  • 實例配置:實力上配置,首先就是要創建一個實例了
const service = axios.create({
  baseURL: 'https://www.monk.com/api',
  timeout: 1000,
})
service.get('/getUserInfo').then(res => {
  console.log(res)
})
  • 請求配置:在請求中配置的優先級最大。
const instance = axios.create();
instance.get('https://www.monk.com/api/fileupload', {
  timeout: 5000
})

當然,我們也可以混合使用:在普通的請求超時1s,在上傳文件時,我們超時5s才阻止請求

const service = axios.create({
  baseURL: 'https://www.monk.com/api',
  timeout: 1000,
})
service.get('/fileupload', {
  timeout: 5000
}).then(res => {
  console.log(res)
})

下面我們再來講解一下併發請求,雖然一般用不到

併發:同時進行多個請求,並統一處理返回值

  • axios.all(iterable)iterable爲需要併發的請求
  • axios.spread(callback)callback是每個請求的回調
const service = axios.create({
  baseURL: 'https://www.monk.com/api',
  timeout: 1000,
})
service.all([
  axios.get('/a'),
  axios.get('/b')
]).then(axios.spread((aRes, bRes) => {
  console.log(aRes, bRes);
}))

上述代碼是併發執行請求/a/b,當請求結束時,在Promise中執行的回調時spread方法,依次調用裏面的回調函數。

攔截器

在axios中,攔截器是非常重要的一個部分,那麼什麼是攔截器呢?

攔截器interceptors,在發起請求之前做一些處理,或在響應回來之後做一些處理。

在這裏插入圖片描述

  • 請求攔截器
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);
  })
  • 移除攔截器
const myInterceptor = axios.interceptors.request.use(config => {});
axios.interceptors.request.eject(myInterceptor);
  • axios實例添加攔截器
const service = axios.create();
service.interceptors.request.use(config => {
    //...
    return config
});

錯誤處理

在請求錯誤時進行的處理,error中有兩個屬性(上下文),request 和response,在錯誤中,如果響應有值,說明響應時出現了錯誤,如果響應沒用值,則說明請求出現了錯誤,如果請求沒用值,則說明請求未發出去,比如請求被取消。

axios.get('https:/monk/api/user')
.catch(function (error) {
    // 錯誤可能是請求錯誤,也可能是響應錯誤
    if (error.response) {
        // 響應錯誤
        console.log(error.response)
    } else if (error.request) {
        // 請求錯誤
        console.log(error.request)
    } else {
        console.log('Error', error.message);
    }
});

在實際開發過程中,一般在攔截器中統一添加錯誤處理,請求攔截器中的錯誤,會當請求未成功發出時執行,但是要注意的是:取消請求後,請求攔截器的錯誤函數也不會執行,因爲取消請求不會拋出異常,axios對其進行了單獨的處理。在更多的情況下,我們會在響應攔截器中處理錯誤。

const instance = axios.create({});
instance.interceptors.request(config => {
	//....
}, error => {
    //錯誤處理
  return Promise.reject(error);
})

instance.interceptors.response(response => {
	//....
}, error => {
    //錯誤處理
  return Promise.reject(error);
})

axios 預檢

當axios的請求爲非簡單請求時,瀏覽器會進行預檢,及發送OPTIONS請求。請求到服務器,詢問是否允許跨域。如果響應中允許預檢中請求的跨域行爲,則瀏覽器會進行真正的請求。否則會報405錯誤。

響應結構

最後再附帶一個axios響應的結構

{
  data: {}, //由服務器提供的響應

  status: 200, //來自服務器響應的 HTTP 狀態碼

  statusText: 'OK', //來自服務器響應的 HTTP 狀態信息

  headers: {}, //服務器響應的頭

  config: {}  // 是爲請求提供的配置信息
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章