vue-axios的總結及項目中的常見封裝方法。

前言

  我們知道 vue 2.0版本開始推薦使用 axios 來完成前端 ajax 請求,axios 是一個基於Promise 的 http 庫,可以用在瀏覽器和 node.js 中,axios 成為vue全家桶的一個重要部分,對前後端介面請求起著必不可少的作用,本文主要總結一下 axios 的一些小知識點和項目中常見的需要封裝的方法。

正文

  1.axios 是什麼?

  axios 是一個基於 Promise 的 http 庫,可以用於瀏覽器和 node.js 中,在瀏覽器中創建 XMLHttpRequest 對象(基於ajax的一種封裝),然後調用該對象的一些方法實現對後端數據介面的請求,在 node.js 中用於創建 http 請求,支援 Promise Api,可以使用 async/await 語法糖書寫,便於攔截請求和響應,並對請求和響應的數據進行處理,自動轉換 JSON 數據格式,同事用於客戶端支援防禦 XSRF。且目前主流瀏覽器都支援該庫。

  常見的安裝方式有以下兩種:

  (1)使用 cdn 方式,程式碼中直接引入下面腳本即可,這種方式適用於小型項目,比如學習的小 demo 等。

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

 

  (2)使用 npm 方式,直接在命令行中添加即可。

    npm install axios

 

  2.axios 常見用法?

  axios中常用的請求配置如下,只有指定的url是必須項,其他存在默認配置項,method不特殊指定,默認方法為 get 。

  {
    url: '/user',
  // `url` 是用於請求的伺服器 URL    method: 'get',
  // default `method` 是創建請求時使用的方法    baseURL: '//some-domain.com/api/',
  // `baseURL` 將自動加在 `url` 前面,除非 `url` 是一個絕對 URL。它可以通過設置一個 `baseURL` 便於為 axios 實例的方法傳遞相對 URL   headers: {'X-Requested-With': 'XMLHttpRequest'},
  // `headers` 是即將被發送的自定義請求頭   params: {   ID: 12345   },
  // 必須是一個無格式對象(plain object)或 URLSearchParams 對象,`params` 是即將與請求一起發送的 URL 參數   timeout: 1000,
  // 如果請求話費了超過 `timeout` 的時間,請求將被中斷,`timeout` 指定請求超時的毫秒數(0 表示無超時時間)   withCredentials: false,
  // default `withCredentials` 表示跨域請求時是否需要使用憑證    responseType: 'json',
  // default `responseType` 表示伺服器響應的數據類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'    responseEncoding: 'utf8', // default   onUploadProgress: function (progressEvent) {
  // `onUploadProgress` 允許為上傳處理進度事件   // Do whatever you want with the native progress event    },    onDownloadProgress: function (progressEvent) {
  // `onDownloadProgress` 允許為下載處理進度事件   // 對原生進度事件的處理    },   }

  (1)get 請求

 

    axios.get('url',{params:{
        //這裡是請求參數
    }})
    .then(res=>{
    //這裡是響應後操作 }) .
catch(err=>{
    //異常捕獲 })

 

  (2)post 請求

    axios.post('url',{  
        name:xxx//參數  
    },{  
        headers:xxxx,//請求頭資訊
    })
    .then(function(res){  
        //處理成功的函數 相當於success
    })
    .catch(function(error){  
        //錯誤處理 相當於error
    })

  (3)all、spread 並發請求

    axios.all([
    axios.get('url'),
    axios.get('url',{params:{type:'sell',page:1}})
    ])
    .then(axios.spread((res1,res2)=>{
        //返回結果為一個數組
    }))

  all()方法入參為一個數組,數組元素是每一項請求,回調函數 .then() 的參數也是一個數組,裡面的每一項元素表示前面請求的返回結果,使用了 axios.spread作為該回調函數的參數時,其res1,res2分別代表前面每一項請求的返回結果。

  綜上這些方法都只使用於小型項目中,或者學習小 demo 中,在工作開發中遇到處理的請求介面較多,

 

  3.axios 在項目中的常見用法?

  (1)小型項目中常見封裝方法,靈活性較高。

  首先創建 axios.js 文件

 

     import originAxios from 'axios'
    export default  function axios(option){
        return new Promise((resolve,reject)=>{
            //創建axios實例
            const instance=originAxios.create({
                baseURL:'/api',
                timeout:5000,
                headers:''
            });
            //傳入對象進行網路請求
            instance(option)
            .then(res=>{
                resolve(res)
            })
            .catch(err=>{
                reject(err)
            })
        })
    }

 

  然後在需要發送請求介面的地方引入

    import {axios} from './axios.js'

    axios({method:"get",url:"url",params:{...}})
    .then(res=>{
        //請求數據後操作
    })
    .catch(err=.{
        //錯誤處理
    })    

 

  (2)針對不同請求類型進行二次封裝。

 

    /* *url:請求的url
       *params:請求的參數
       *config:請求時的header資訊
       *method:請求方法 */
      const request = function ({ url, params, config, method }) {
        // 如果是get請求 需要拼接參數
        let str = "";
        if (method === "get" && params) {
          Object.keys(params).forEach((item) => {
            str += `${item}=${params[item]}&`;
          });
        }
        return new Promise((resolve, reject) => {
          axios[method](
            str ? url + "?" + str.substring(0, str.length - 1) : url,
            params,
            Object.assign({}, config)
          )
            .then(
              (response) => {
                resolve(response.data);
              },
              (err) => {
                if (err.Cancel) {
                } else {
                  reject(err);
                }
              }
            )
            .catch((err) => {
              reject(err);
            });
        });
      };

 

  具體使用同上。

  (3)基於請求響應攔截進行封裝,實際項目開發中常用。

  axios 提供的攔截器,用於每次發送請求和得到響應後進行響應的處理。比如在請求攔截中可以在頁面中添加 loading 動畫,某些請求要求用戶必須登錄,判斷用戶是否有token,如果沒有就跳轉到登錄頁面等,也可以對請求參數進行序列化操作等 config.data = qs.stringfy(config.params) 等。同樣,響應攔截也可以對響應的數據進行過濾,包括響應失敗的攔截,可以根據響應狀態碼進行不同的操作等。具體方法如下:

  首先在工具方法文件夾中創建 request.js 文件。這裡搭配了token用於判斷用戶狀態,element-ui 組件處理一些錯誤報錯提示。該文件封裝暴露了get、post、文件上傳方法。

 

      import axios from "axios";
      import store from "../store";
      import { Message, MessageBox } from "element-ui";

      let baseURL = "//127.0.0.1:3000/";
      // 創建axios實例
      const service = axios.create({
        baseURL: baseURL,
        timeout: 5000, // 請求超時時間
        headers: { "Content-Type": "application/json;charset=UTF-8" },
      });
      // axios.defaults.withCredentials = true; // 若跨域請求需要帶 cookie 身份識別
      axios.defaults.headers.post["Access-Control-Allow-Origin-Type"] = "*"; // 允許跨域
      const err = (error) => {
        if (error.response) {
          let data = error.response.data;
          const token = store.getters.token;
          switch (error.response.status) {
            case 403:
              Message({
                message: data.message,
                type: "error",
                duration: 5 * 1000,
              });
              break;
            case 500:
              if (token && data.message == "Token失效,請重新登錄") {
                MessageBox.confirm(
                  "很抱歉,登錄已過期,請重新登錄",
                  "確定登出",
                  {
                    confirmButtonText: "重新登錄",
                    cancelButtonText: "取消",
                    type: "warning",
                  }
                ).then(() => {
                  store.dispatch("Logout").then(() => {
                    window.location.reload(); // 為了重新實例化vue-router對象 避免bug
                  });
                });
              }
              break;
            case 404:
              Message({
                message: data.message,
                type: "error",
                duration: 5 * 1000,
              });

              break;
            case 504:
              Message({
                message: data.message,
                type: "error",
                duration: 5 * 1000,
              });
              break;
            case 401:
              Message({
                message: data.message,
                type: "error",
                duration: 5 * 1000,
              });
              if (token) {
                store.dispatch("Logout").then(() => {
                  setTimeout(() => {
                    window.location.reload();
                  }, 1500);
                });
              }
              break;
            default:
              Message({
                message: data.message,
                type: "error",
                duration: 5 * 1000,
              });
              break;
          }
        }
        return Promise.reject(error);
      };
      // request攔截器
      service.interceptors.request.use(
        (config) => {
          const token = store.getters.token;
          if (store.getters.token) {
            config.headers["X-Token"] = token;
          }
          return config;
        },
        (error) => {
          // Do something with request error
          console.log(error); // for debug
          Promise.reject(error);
        }
      );
      // respone攔截器
      service.interceptors.response.use((response) => {
        console.log("response.data", response.data);
        return response.data;
      }, err);

      /*
       *  get請求
       *  url:請求地址
       *  params:參數
       * */
      export function get(url, params = {}) {
        return new Promise((resolve, reject) => {
          console.log("process.env.BASE_API", process.env.BASE_API);
          service({
            url: url,
            method: "get",
            params: params,
          })
            .then((response) => {
              resolve(response);
            })
            .catch((error) => {
              reject(error);
            });
        });
      }

      /*
       *  post請求
       *  url:請求地址
       *  params:參數
       * */
      export function post(url, params = {}) {
        return new Promise((resolve, reject) => {
          service({
            url: url,
            method: "post",
            data: params,
          })
            .then((response) => {
              resolve(response);
            })
            .catch((error) => {
              reject(error);
            });
        });
      }

      /*
       *  文件上傳
       *  url:請求地址
       *  params:參數
       * */
      export function fileUpload(url, params = {}) {
        return new Promise((resolve, reject) => {
          console.log("@@@@@@@@@@@params", params);
          service({
            url: url,
            method: "post",
            data: params,
            headers: { "Content-Type": "multipart/form-data" },
          })
            .then((response) => {
              resolve(response);
            })
            .catch((error) => {
              reject(error);
            });
        });
      }

      export default {
        get,
        post,
        fileUpload,
      };

 

  然後創建api文件夾,如果介面過多可以對介面進行模組化管理,比如我這 api 下面創建 login.js 文件。

import { get, post,fileUpload } from "../utils/request";

// 登錄
export const login = (params) => {
  return get("/user/login", { ...params });
};
// 查詢用戶資訊
export const getUserInfo = (params) => {
  return get("/user/userInfo", { ...params });
};
// 上傳音頻文件
export const addRadioApi = (params, file) => {
  return fileUpload("/radio/addRadio", { params, file });
};

  最後在你的vue文件中就可以使用了,login.vue中使用如下:

      import { login } from "../../api/login";
      login({ name: "123", password: "123456" })
        .then((res) => {
          //登錄請求後操作
        })
        .catch((error) => {
          //異常處理
        });

總結

  以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長踩坑之路會持續更新一些工作中常見的問題和技術點。

 

Tags: