在ajaxRequest.js中对Axios进行封装,并且配置全局loading,并把JWT Token加入到请求头里面

1,080 阅读4分钟

不管是 PC端 还是 移动端,都必须使用 ajaxRequest.js

1. 先在 src 目录, 新建 utils/ajaxRequest.js 。

在 ajaxRequest.js 将 Axios 进行封装。

ajaxRequest.js :

// 对 Axios 的封装
// 1.配置全局 loading
// 2.在请求头里加入 JWT Token, Token 一定要加入到拦截器
// 3.拦截器,可以对响应的结果,统一进行处理
import axios from 'axios'

// 导入 store
import store from '../store/index'

// 将 JWT Token 从localStorage中取出来, 加入到请求头中
import { getLocal } from './local'

class AjaxRequest {
  // 配置一些默认参数
  // 每一次请求,都会走这个构造函数
  constructor () {
    // 请求的路径
    this.baseURL =
      process.env.NODE_ENV == 'production' ? '/' : 'http://localhost:3000'
    this.timeout = 3000 // 超时时间,3S
    this.method = 'GET' // 默认方法为 'GET'
    this.queue = {} // 队列,配置全局 loading。存放每次的请求 url
  }

  // 默认的参数,和传进来的参数,进行合并
  merge (options) {
    return { ...options, baseURL: this.baseURL, timeout: this.timeout }
  }
  setInterceptor (instance, url) {
    // 对请求进行拦截
    // 对每一次请求,进行拦截
    // 1.更改请求头,将 Token 加入到请求头
    // 2.每次请求时,都会加一个loading 效果
    instance.interceptors.request.use(
      config => {
        console.log(config)
        // config.headers['X-Auth-Token'] = 'xxxx' // 在请求头中加入了 X-Auth-Token 属性
        config.headers['X-Auth-Token'] = getLocal('auth_token') // 将 JWT Token 加入到请求头中
        config.headers.Authorization = 'xxx'

        // 当第一次请求,显示loading, 剩下的时候,就不显示了
        // 当都请求完毕后,去隐藏loading
        if (Object.keys(this.queue).length === 0) {
          // 如果对象为空,则表明是第一次,那么显示 loading
          // 在请求之前,显示loading
          store.commit('showLoading')
        }

        this.queue[url] = url // 把请求的url存入 queue对象
        return config
      },
      err => {
        return Promise.reject(err)
      }
    )

    // 对响应的数据,进行拦截
    // 如果上一个promise返回了一个常量,会作为下一个promise的输入
    instance.interceptors.response.use(
      res => {
        // 响应一次,就把 queue对象中的url,删掉一个
        delete this.queue[url]

        // 如果queue对象为空,则表明 url被删完了,则最后一次的请求结束了
        // 那么就隐藏 loading
        // 这样就能保证,loading只显示一次。 并且只隐藏一次。
        // 最迟不超过3S。
        if (Object.keys(this.queue).length === 0) {
          // 在响应之前,隐藏loading
          store.commit('hideLoading')
        }

        // 对响应的状态码,进行统一处理
        if (res.status === 304) {
          return Promise.reject(res.status)
        }

        // 对每一次请求的数据,进行拦截
        return res.data
      },
      err => {
        return Promise.reject(err)
      }
    )
  }
  request (options) {
    // url, method
    let instance = axios.create() // 通过axios库创建一个axios实例
    this.setInterceptor(instance, options.url)
    let config = this.merge(options)
    // axios执行后返回的是一个promise
    return instance(config) // 前面加return。 其他组件可以这样用:axios.request().then()
  }
}

export default new AjaxRequest()

// 在其他组件使用:
// import axios from './utils/ajaxRequest.js'
// axios.request({
//   url: '/user',
//   method: 'post'
// }).then()

2. 在 utils 目录新建 local.js ,封装一些本地存储的方法

local.js:

// 本地存储

// 存入 localStorage
export const setLocal = (key, value) => {
  if (typeof value === 'object') {
    value = JSON.stringify(value)
  }
  localStorage.setItem(key, value)
}

// 取localStorage中的值
export const getLocal = key => {
  return localStorage.getItem(key)
}

// 存入sessionStorage
export const setSession = (key, value) => {
  if (typeof value === 'object') {
    value = JSON.stringify(value)
  }
  sessionStorage.setItem(key, value)
}

// 取sessionStorage中的值
export const getSession = key => {
  return sessionStorage.getItem(key)
}

3. 在 App.vue 页面里,加入 loading 的组件

使用的 UI框架是 vue ant design

App.vue:

<template>
  <div id="app">

    <!-- loading -->
    <a-spin v-if="$store.state.isShowLoading">
      <a-icon slot="indicator"
              type="loading"
              style="font-size: 48px"
              spin />
    </a-spin>

    <router-view />

    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/login">Login</router-link> |
      <router-link to="/profile">Profile</router-link>
    </div>

  </div>
</template>

<style lang="less">
/* loading */
.ant-spin-spinning {
  z-index: 1500;
  position: fixed !important;
  top: 50% !important;
}
</style>

4. 在 api/user.js 中使用 ajaxRequest.js

user.js:

// 用户登录接口

// 专门写,调取后端的接口
import axios from '../utils/ajaxRequest'

export const getUser = () => {
  // return 以后,在其他组件,调用: getUser().then()
  // import { getUser } from './api/user'
  // getUser().then(data => {})
  return axios.request({
    url: '/user',
    method: 'get'
  })
}

// 登录方法
// 传入用户名和密码
export const login = (username, password) => {
  return axios.request({
    method: 'POST',
    url: '/login',
    data: {
      username,
      password
    }
  })
}

// 在main.js 中的beforeEach中,去校验用户是否登录
export const validate = () => {
  return axios.request({
    method: 'get',
    url: '/validate'
  })
}

5. 在 actions 中,调用 api/user.js 中的方法

store/index.js:

import Vue from 'vue'
import Vuex from 'vuex'

import { login, validate } from '../api/user'
// import * as types from './mutation-types'

import { setLocal } from '../utils/local' // 将JWT Token 存入 localStorage

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    isShowLoading: false, // 是否显示loading效果
    username: 'x' // 登录后的用户名
  },
  mutations: {
    showLoading (state) {
      state.isShowLoading = true // 显示loading
    },
    hideLoading (state) {
      state.isShowLoading = false // 隐藏loading
    },
    setUser (state, username) {
      state.username = username // 更改公共状态
    }
  },
  // 在actions中,去调取 api/user.js 中的方法
  // 然后,在组件中,去触发 actions 中的方法
  actions: {
    // 一般在actions中,写接口调用
    async doLogin ({ commit }, payload) {
      console.log(payload.username)
      console.log(payload.password)
      // store.dispatch('doLogin')
      let res = await login(payload.username, payload.password)
      // 登录成功
      if (res.code === 0) {
        // 把用户名存入 Vuex
        commit('setUser', res.username)

        // 将返回客户端的JWT Token保存到客户端上,每次请求时,请求头上加上Token,
        // 然后服务端校验 Token, 如果Token不正确,或者过期,则相当于没有登录
        setLocal('auth_token', res.auth_token)
      } else {
        // 返回的失败的promise
        return Promise.reject(res.data)
      }
    },

    // 在 main.js 中的beforeEach 去校验用户是否登录
    async doValidate ({ commit }) {
      let res = await validate()
      // 表示已登录过
      if (res.code === 0) {
        // 再给username设置一次值
        commit('setUser', res.username)

        // 再把校验后的Token,再存入客户端一次,从而延长时效。
        setLocal('auth_token', res.auth_token)
      }
      return res.code === 0 // 返回用户是否已登录, true表示已登录, false表示用户失效
    }
  }
})

// 在组件中,调用
// store.dispatch('doLogin').then(data, err=> {
//   console.log('xxxx')
// })

6. 关于使用 ajaxRequest.js 的注意点

在其他组件中使用:

// 在其他组件使用:
import axios from './utils/ajaxRequest.js'
axios.request({
    url: '/user',
    method: 'post'
}).then()