mpvue+vuex封裝wx.request管理token

一開始網上查資料看到mpvue中封裝wx.request返回promise對象,感覺這樣就夠用了,也就沒有用axios、flyio等庫,後面需要結合token管理的時候就比較苦逼了,接下來的內容跟axios、flyio等內容完全不搭邊,flyio等如果想管理token的話,需要做請求攔截,具體可以自行百度。

一、封裝wx.request

在src/utils目錄下新建requestMethod.js文件進行請求封裝,可以新建config.js文件作爲配置文件,存放請求基地址。

config.js:

const baseUrl = 'https://www.zwl.com/api/v1'
const tokenUrl = 'https://www.zwl.com/api/v1/token/user'

export default{
  baseUrl,
  tokenUrl
}

在使用的時候調用get方法,會在return處執行request(),request會返回一個Promise實例,在Promise實例化的時候發送了請求,requestMethod.js:

import Config from './config'

function request (url, method, data, header = {}) {
  wx.showLoading({
    title: '加載中' //  數據請求前loading
  })
  return new Promise((resolve, reject) => {
    wx.request({
      url: Config.baseUrl + url,
      method: method,
      data: data,
      header: {
        'content-type': 'application/json'
      },
      success: function (res) {
        wx.hideLoading()
        resolve(res.data)
      },
      fail: function (error) {
        wx.hideLoading()
        reject(error)
      },
      complete: function () {
        wx.hideLoading()
      }
    })
  })
}
function get (obj) {
  return request(obj.url, 'GET', obj.data)
}
function post (obj) {
  return request(obj.url, 'POST', obj.data)
}

export default {
  request,
  get,
  post
}

使用前需要將封裝的請求掛在Vue原型上,被所有vue實例共享(相當於定義了全局變量,在.vue文件中可以直接使用)。src/main.js如下:

import Vue from 'vue'
import App from './App'
import request from './utils/requestMethod'

// 將request賦值給Vue原型鏈上的$http屬性($http屬性將被創建)
Vue.prototype.$http = request
Vue.config.productionTip = false
App.mpType = 'app'

const app = new Vue(App)
app.$mount()

在src/pages/index/index.vue中使用如下:

<template>
  <div></div>
</template>
<script>

export default {
  data () {
    return {
      dataList: []
    }
  },
  methods: {
    //  初始化數據
    initData () {
      this.$http.post({
        url: '/collection/is_collect/',
        data: {'id': 7}
      }).then((res) => {
        //    請求成功執行回調,開始初始化數據
        this.dataList = res.data
        
      })
    }
  },
  created () {
    //    在vue實例創建時執行數據初始化
    this.initData()
  }
}
</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>

二、vuex管理token

在src下新建目錄store,store目錄如下:

把要管理的數據放入state.js文件:

const state = {
  token: ''
}

export default state

在mutation-types.js中定義類型(想不到詞形容這個文件的作用,直接看操作吧):

//    設置token
export const SET_TOKEN = 'SET_TOKEN'
//    更新token
export const UPDATE_TOKEN = 'UPDATE_TOKEN'

在mutations.js文件中對數據進行操作,這裏我們同時把token存入本地緩存:

import * as types from './mutation-types'

const matations = {
  /**
   * state: 當前狀態樹
   * v: 提交matations時傳的參數
   * 設置token時執行的操作
   */
  [types.SET_TOKEN] (state, v) {
    state.token = v
    //  同步存入本地緩存
    wx.setStorageSync('token', v)
  },
  //  更新token時執行的操作  
  [types.UPDATE_TOKEN] (state, v) {
    state.token = v
    wx.setStorageSync('token', v)
  }
}

export default matations

 在src/store/index.js中進行組裝:

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

import state from './state'
import getters from './getters'
import actions from './actions'
import mutations from './mutations'

Vue.use(Vuex)

export default new Vuex.Store({
  state,
  getters,
  actions,
  mutations
})

在src/main.js中將store掛在原型上:

import store from './store/index'

Vue.prototype.$store = store

使用示例:

//   注意‘UPDATE_TOKEN’將執行mutations下的[types.UPDATE_TOKEN]對應的操作

this.$store.commit('UPDATE_TOKEN', token的新值) 

三、攜帶token訪問API

以下是根據個人開發的小程序裏設計的token管理流程

根據流程圖,主要是在訪問API後對返回的狀態進行判斷,是否出現token過期或者token爲空的狀態,然後重新獲取token,再重發當前請求。首先,封裝一個方法用作從服務器獲取token,src/utils/token.js:

import Config from './config'

//  從服務器獲取token
function getTokenFromServer () {
  return new Promise((resolve, reject) => {
    wx.login({
      success: function (res) {
        wx.request({
          url: Config.tokenUrl,
          method: 'POST',
          data: {
            code: res.code
          },
          success: function (res) {
            //    取得token後需要對現在的token進行更新
            this.$store.commit('UPDATE_TOKEN', res.data.token)
            resolve(res.data)
          }
        })
      }
    })
  })
}

這裏可能會出現錯誤說$store undefined;

這裏可能原因是this的指向問題,這裏的this指向是當前js文件,所以需要想辦法引入vue實例,vue實例可以使用$store變量: 

之後需要重寫之前封裝的請求,requestMethod.js: 

四、全部代碼:

 requestMethod.js:

import Config from './config'
import Token from './token'

function request (url, method, data, header = {}, noRefetch = false) {
  wx.showLoading({
    title: '加載中' //  數據請求前loading
  })
  return new Promise((resolve, reject) => {
    wx.request({
      url: Config.baseUrl + url,
      method: method,
      data: data,
      header: {
        'token': wx.getStorageSync('token'),
        'content-type': 'application/json'
      },
      success: function (res) {
        wx.hideLoading()
        let code = res.statusCode.toString()
        let startChar = code.charAt(0)
        if (startChar === '2') {
          resolve(res.data)
        } else {
          if (code === '401') {
            if (!noRefetch) {
              Token.getTokenFromServer().then((token) => {
                //  獲取token之後重新發送請求
                request(url, method, data, {}, true).then((res) => {
                  resolve(res)
                })
              })
            }
          }
        }
      },
      fail: function (error) {
        wx.hideLoading()
        reject(error)
      },
      complete: function () {
        wx.hideLoading()
      }
    })
  })
}
function get (obj) {
  return request(obj.url, 'GET', obj.data)
}
function post (obj) {
  return request(obj.url, 'POST', obj.data)
}

export default {
  request,
  get,
  post
}

token.js:

import Config from './config'
import Vue from 'vue'

let vue = new Vue()

function verify () {
  let token = wx.getStorageSync('token')
  if (!token) {
    // 不存在token緩存,獲取token
    getTokenFromServer()
  } else {
    // 對緩存中的token進行驗證
    verifyFromServer(token)
  }
}

//  從服務器獲取token
function getTokenFromServer () {
  return new Promise((resolve, reject) => {
    wx.login({
      success: function (res) {
        wx.request({
          url: Config.tokenUrl,
          method: 'POST',
          data: {
            code: res.code
          },
          success: function (res) {
            vue.$store.commit('UPDATE_TOKEN', res.data.token)
            resolve(res.data.token)
          }
        })
      }
    })
  })
}

// 攜帶令牌去服務器校驗
function verifyFromServer (token) {
  wx.request({
    url: Config.tokenUrl,
    method: 'POST',
    data: {
      token: token
    },
    success: function (res) {
      let valid = res.data.isValid
      if (!valid) {
        getTokenFromServer()
      }
    }
  })
}

export default{
  verify,
  getTokenFromServer,
  verifyFromServer
}

main.js:

import Vue from 'vue'
import App from './App'
import request from './utils/requestMethod'
import store from './store/index'

Vue.prototype.$store = store
Vue.prototype.$http = request
Vue.config.productionTip = false
App.mpType = 'app'

const app = new Vue(App)
app.$mount()

使用時,如果當前token無效可以在調試的時候看到當前網絡請求發送了兩次,第一次爲401,第二次爲成功狀態:

<template>
  <div></div>
</template>
<script>

export default {
  data () {
    return {
      dataList: []
    }
  },
  methods: {
    //  初始化數據
    initData () {
      this.$http.post({
        url: '/collection/is_collect/',
        data: {'id': 7}
      }).then((res) => {
        //    請求成功執行回調,開始初始化數據
        this.dataList = res.data
        
      })
    }
  },
  created () {
    //    在vue實例創建時執行數據初始化
    this.initData()
  }
}
</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章