Vue axios获取token临时令牌封装

前言

为什么非要写这个博客呢?因为这件事让我有一种蛋蛋的优疼。剩下的都别问,反正问我也不会说。因为流程图我都不想(懒得)画。

开发架构

  1. 前端页面:Vue
  2. 网络请求:Axios;方式:vue add axios
  3. 缓存方案
    • 全局变量:Vuex
    • 本地缓存:LocalStorage

技术依赖

你猜

背景

公司开发一个嵌入App的Web页面,安全方面使用老套路:App通过URL传参给前端(包含签名),前端把参数透传给H5后端验签,完事儿之后前端再决定用户是否合法。另外定义了N个JS方法前端根据固定GET参数判断是安卓还是苹果来调用。

初步设想

关于token设计方案的初步设想是这样的:第一次进入的时候获取token,后端检查签名是否通过。不通过则弹框请从合法途径进入页面并且不消失。
否则就可以让用户继续后续操作,直到后端返回token过期特定状态码回来前端在用户无感的情况下调用JS方法重新获取URL参数请求token,完事儿之后继续用户的请求操作。(为避免用户使用旧token在其他地方操作数据,每次获取token都重新从App中获取并验证,而不是在接口中刷新并返回新的token)

蛋疼事项

  1. 一期的时候定义URL参数时没有版本控制,导致二期新增JS方法迭代版本时前端新增页面调用了未知方法页面毫无反应;埋点数据也不知道是几期的…
  2. 为尽量避免请求过程中出现token过期导致的1次请求变3次请求现象每次调用请求之前需要先检查token时效的异步方法(如果token过期则调用getToken获取新的token并存储在本地)导致block嵌套。
  3. 后面又封装了N个方法就不说了…

升级设想

版本什么的这个先不说,就这个token问题我总不能每次新增一个请求就复制粘贴复制粘贴的吧?能烦死人!那我只能在axios请求之前判断token时效性啦。

直奔主题

  • 函数声明

    1. getToken:从本地取已存储token
    2. checkToken:检查token时效,失效调用refreshToken函数成功则存储本地,否则返回错误原因
    3. refreshToken:调用JS方法从App获取签名参数重新请求token
  • 注意事项

    1. 在checkToken过程中token过期时,先移除本地已过期token缓存数据。
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */
"use strict";

import Vue from 'vue';
import axios from "axios";
import { getToken } from '../utils/storage.js'
import { checkToken, refreshToken, clearCache } from "../utils/utils.js";

// Full config:  https://github.com/axios/axios#request-config
// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.headers.post["Content-Type"] = "application/json";

let cancel,
  promiseArr = {};
let config = {
  baseURL: process.env.VUE_APP_BASE_URL,
  timeout: 8 * 1000, // Timeout
  withCredentials: true, // Check cross-site Access-Control
};

const _axios = axios.create(config);

_axios.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    let token = getToken();
    // alert("token1:" + token);
    //发起请求时,取消掉当前正在进行的相同请求
    if (promiseArr[config.url]) {
      promiseArr[config.url]("请稍后");
      promiseArr[config.url] = cancel;
    } else {
      promiseArr[config.url] = cancel;
    }
    if (token) {
      return checkToken(null)
          .then((result) => {
            // console.log("refreshToken result:", result);
            if (result === true) {
              token = getToken()
              // alert("token2:" + token);
              config.headers.common["authorization"] = token;
              return config;
            } else {
              return Promise.reject(Error(result))
            }
          }).catch((err) => {
            // 终止这个请求
            return Promise.reject(err);
          });
    }
    return config;
  },
  function (error) {
    // Do something with request error
    return Promise.reject(error);
  }
);

// Add a response interceptor
_axios.interceptors.response.use(
  function (response) {
    // Do something with response data
    let { status, statusText, data } = response;
    if (err_check(status, statusText, data) && data) {
      // var randomColor = `rgba(${parseInt(Math.random() * 255)},${parseInt(
      //   Math.random() * 255
      // )},${parseInt(Math.random() * 255)})`;

      // console.log(
      //   "%c┍------------------------------------------------------------------┑",
      //   `color:${randomColor};`
      // );
      // console.log("| 请求地址:", response.config.url);
      // console.log("| 请求参数:", response.config.data);
      // console.log("| 返回数据:", response.data);
      // console.log(
      //   "%c┕------------------------------------------------------------------┙",
      //   `color:${randomColor};`
      // );
      if (data.resCode === "0001") {
        clearCache()
        var config = response.config;
        var url = config.url;
        url = url.replace("/apis", "").replace(process.env.VUE_APP_BASE_URL, "")
        config.url = url;
        // alert(JSON.stringify(config))
        return refreshToken(null)
          .then((result) => {
            // console.log("refreshToken result:", result);
            if (result == true) {
              let token = getToken()
              if (token) {
                config.headers["authorization"] = token;
              }
              return axios(config)
                .then((result) => {
                let { status, statusText, data } = result;
                // console.log('接口二次请求 result:', result);
                if (err_check(status, statusText, data) && data) {
                  return Promise.resolve(data)
                } else {
                  return Promise.reject(Error(data.resDesc));
                }
              }).catch((err) => {
                // console.log('接口二次请求 err:' + err);
                return Promise.reject(err);
              });
            } else {
              // alert("result:" + result)
              return Promise.reject(Error(data.resDesc))
            }
          }).catch((err) => {
            // 终止这个请求
            // alert("终止这个请求:" + err.message)
            // console.log("refreshToken err:", err);
            return Promise.reject(err);
          });
      } else {
        return Promise.resolve(data);
      }
    } else {
      return Promise.reject(Error(statusText));
    }
    // return response;
  },
  function (error) {
    // Do something with response error
    // console.log("error", error);
    return Promise.reject(error);
  }
);

// eslint-disable-next-line no-unused-vars
const err_check = (code, message, data) => {
  if (code == 200) {
    return true;
  }
  return false;
};

Plugin.install = function (Vue, options) {
  Vue.axios = _axios;
  window.axios = _axios;
  Object.defineProperties(Vue.prototype, {
    axios: {
      get() {
        return _axios;
      }
    },
    $axios: {
      get() {
        return _axios;
      }
    },
  });
};

Vue.use(Plugin)

export default Plugin;

你可能感兴趣的:(技术笔记)