1. 程式人生 > >給axios做個挺靠譜的封裝(報錯,鑑權,跳轉,攔截,提示

給axios做個挺靠譜的封裝(報錯,鑑權,跳轉,攔截,提示

前言

不推薦完全copy過去,可以看看我是如何針對我這邊業務;
做的一個axios的封裝及實現的思路

需求及實現

  • 統一捕獲介面報錯
  • 彈窗提示
  • 報錯重定向
  • 基礎鑑權
  • 表單序列化

實現的功能

  • 統一捕獲介面報錯 : 用的axios內建的攔截器
  • 彈窗提示: 引入 Element UIMessage元件
  • 報錯重定向: 路由鉤子
  • 基礎鑑權: 服務端過期時間戳和token,還有藉助路由的鉤子
  • 表單序列化: 我這邊直接用qs(npm模組),你有時間也可以自己寫

效果圖

坑都已經爬過,現在復現那些錯誤有點麻煩..所以沒法錄製動態圖

用法及封裝

  • 用法
// 服務層 , import預設會找該目錄下index.js的檔案,這個可能有小夥伴不知道
// 可以去了解npm的引入和es6引入的理論概念
import axiosPlugin from "./server"; Vue.use(axiosPlugin);
  • 對axios的封裝(AXIOS:index.js)
import axios from "axios";
import qs from "qs";
import { Message } from "element-ui";
import router from "../router";

const Axios = axios.create({
  baseURL: "/", // 因為我本地做了反向代理
  timeout: 10000,
  responseType: "json",
  withCredentials
: true, // 是否允許帶cookie這些 headers: { "Content-Type": "application/x-www-form-urlencoded;charset=utf-8" } }); //POST傳參序列化(新增請求攔截器) Axios.interceptors.request.use( config => { // 在傳送請求之前做某件事 if ( config.method === "post" || config.method === "put" || config.method === "delete"
) { // 序列化 config.data = qs.stringify(config.data); } // 若是有做鑑權token , 就給頭部帶上token if (localStorage.token) { config.headers.Authorization = localStorage.token; } return config; }, error => { Message({ // 餓了麼的訊息彈窗元件,類似toast showClose: true, message: error, type: "error.data.error.message" }); return Promise.reject(error.data.error.message); } ); //返回狀態判斷(新增響應攔截器) Axios.interceptors.response.use( res => { //對響應資料做些事 if (res.data && !res.data.success) { Message({ // 餓了麼的訊息彈窗元件,類似toast showClose: true, message: res.data.error.message.message ? res.data.error.message.message : res.data.error.message, type: "error" }); return Promise.reject(res.data.error.message); } return res; }, error => { // 使用者登入的時候會拿到一個基礎資訊,比如使用者名稱,token,過期時間戳 // 直接丟localStorage或者sessionStorage if (!window.localStorage.getItem("loginUserBaseInfo")) { // 若是介面訪問的時候沒有發現有鑑權的基礎資訊,直接返回登入頁 router.push({ path: "/login" }); } else { // 若是有基礎資訊的情況下,判斷時間戳和當前的時間,若是當前的時間大於伺服器過期的時間 // 乖乖的返回去登入頁重新登入 let lifeTime = JSON.parse(window.localStorage.getItem("loginUserBaseInfo")).lifeTime * 1000; let nowTime = new Date().getTime(); // 當前時間的時間戳 console.log(nowTime, lifeTime); console.log(nowTime > lifeTime); if (nowTime > lifeTime) { Message({ showClose: true, message: "登入狀態資訊過期,請重新登入", type: "error" }); router.push({ path: "/login" }); } else { // 下面是介面回撥的satus ,因為我做了一些錯誤頁面,所以都會指向對應的報錯頁面 if (error.response.status === 403) { router.push({ path: "/error/403" }); } if (error.response.status === 500) { router.push({ path: "/error/500" }); } if (error.response.status === 502) { router.push({ path: "/error/502" }); } if (error.response.status === 404) { router.push({ path: "/error/404" }); } } } // 返回 response 裡的錯誤資訊 let errorInfo = error.data.error ? error.data.error.message : error.data; return Promise.reject(errorInfo); } ); // 對axios的例項重新封裝成一個plugin ,方便 Vue.use(xxxx) export default { install: function(Vue, Option) { Object.defineProperty(Vue.prototype, "$http", { value: Axios }); } };
  • 路由鉤子的調整(Router:index.js)

import Vue from "vue";
import Router from "vue-router";
import layout from "@/components/layout/layout";
// 版塊有點多,版塊獨立路由管理,裡面都是懶載入引入
import customerManage from "./customerManage"; // 客戶管理
import account from "./account"; //登入
import adManage from "./adManage"; // 廣告管理
import dataStat from "./dataStat"; // 資料統計
import logger from "./logger"; // 日誌
import manager from "./manager"; // 管理者
import putonManage from "./putonManage"; // 投放管理
import error from "./error"; // 服務端錯誤
import { Message } from "element-ui";

Vue.use(Router);

// 請跳過這一段,看下面的
const router = new Router({
  hashbang: false,
  mode: "history",
  routes: [
    {
      path: "/",
      redirect: "/adver",
      component: layout,
      children: [
        ...customerManage,
        ...adManage,
        ...dataStat,
        ...putonManage,
        ...manager,
        ...logger
      ]
    },
    ...account,
    ...error
  ]
});

// 路由攔截
// 差點忘了說明,不是所有版塊都需要鑑權的
// 所以需要鑑權,我都會在路由meta新增新增一個欄位requireLogin,設定為true的時候
// 這貨就必須走鑑權,像登入頁這些不要,是可以直接訪問的!!!
router.beforeEach((to, from, next) => {
  if (to.matched.some(res => res.meta.requireLogin)) {
    // 判斷是否需要登入許可權
    if (window.localStorage.getItem("loginUserBaseInfo")) {
      // 判斷是否登入
      let lifeTime =
        JSON.parse(window.localStorage.getItem("loginUserBaseInfo")).lifeTime *
        1000;
      let nowTime = (new Date()).getTime(); // 當前時間的時間戳
      if (nowTime < lifeTime) {
        next();
      } else {
        Message({
          showClose: true,
          message: "登入狀態資訊過期,請重新登入",
          type: "error"
        });
        next({
          path: "/login"
        });
      }
    } else {
      // 沒登入則跳轉到登入介面
      next({
        path: "/login"
      });
    }
  } else {
    next();
  }
});

export default router;

axios可配置的一些選項,其他的具體看官網說明哈


export default {
  // 請求地址
  url: "/user",
  // 請求型別
  method: "get",
  // 請根路徑
  baseURL: "http://www.mt.com/api",
  // 請求前的資料處理
  transformRequest: [function(data) {}],
  // 請求後的資料處理
  transformResponse: [function(data) {}],
  // 自定義的請求頭
  headers: { "x-Requested-With": "XMLHttpRequest" },
  // URL查詢物件
  params: { id: 12 },
  // 查詢物件序列化函式
  paramsSerializer: function(params) {},
  // request body
  data: { key: "aa" },
  // 超時設定s
  timeout: 1000,
  // 跨域是否帶Token
  withCredentials: false,
  // 自定義請求處理
  adapter: function(resolve, reject, config) {},
  // 身份驗證資訊
  auth: { uname: "", pwd: "12" },
  // 響應的資料格式 json / blob /document /arraybuffer / text / stream
  responseType: "json",
  // xsrf 設定
  xsrfCookieName: "XSRF-TOKEN",
  xsrfHeaderName: "X-XSRF-TOKEN",

  // 下傳和下載進度回撥
  onUploadProgress: function(progressEvent) {
    Math.round(progressEvent.loaded * 100 / progressEvent.total);
  },
  onDownloadProgress: function(progressEvent) {},

  // 最多轉發數,用於node.js
  maxRedirects: 5,
  // 最大響應資料大小
  maxContentLength: 2000,
  // 自定義錯誤狀態碼範圍
  validateStatus: function(status) {
    return status >= 200 && status < 300;
  },
  // 用於node.js
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 用於設定跨域請求代理
  proxy: {
    host: "127.0.0.1",
    port: 8080,
    auth: {
      username: "aa",
      password: "2123"
    }
  },
  // 用於取消請求
  cancelToken: new CancelToken(function(cancel) {})
};

總結

我這個封裝雖說不是萬金油版本,但是我感覺大多用axios結合vue的小夥伴,
稍微改改都能直接拿來用~~~喲吼吼,喲吼吼.....