首页 > 解决方案 > 刷新令牌后,将原始请求的响应存储在 vuex 存储中

问题描述

我有一个 vuex 模块,其中包含通过 axios 支持的服务向 API 发出请求的操作。请求成功后,我使用模块的突变将响应存储在本地。

我使用 JWT 令牌对调用进行身份验证。我的身份验证令牌可能会过期,当它过期时,我会调用 API 以刷新令牌。

我使用拦截器来检测响应是否为 401,存储原始请求,调用刷新令牌并进行包含刷新令牌的原始调用。

目前,我有两个问题:

  1. 因为模块中不再发生调用,所以我无法存储响应。
  2. 模块中的第一个请求失败,因此我将错误消息发送到突变。

我有办法维护原始链并使第二个请求响应返回到模块吗?

axios.js

import axios from 'axios';
import { authService } from '@/services'

import store from '@/store'
import i18n from '@/i18n.js';

function isExpiredTokenError(data) {
  return (data.errors && data.errors.find((error) => error.code == 'expired_token'))
}

function storeToken({ access_token, refresh_token }) {
  /* do some stuff to store the token in localStorage and the a vuex store */ 

  axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;
}

function refreshExpiredToken(originalConfig) {
  originalConfig._retry = true;

  const storedRefreshToken = store.state.auth.refreshToken

  authService.refreshToken(storedRefreshToken)
    .catch(function (error) {
      if (error.response) {
        delete axios.defaults.headers.common['Authorization']
        store.dispatch('auth/logout', { error: i18n.t('errors.need_to_relog') })
      }
      return Promise.reject(error);
    })
    .then(response => {
      const oauthToken = response['data']
      storeToken(oauthToken)
      return axios(originalConfig);  
    })
}

const requestInterceptor = axios.interceptors.request.use(function (config) {
  const accessToken = store.state.auth.accessToken;

  if (accessToken)
    config.headers.Authorization = `Bearer ${accessToken}`;

  return config;

}, function (err) {
  return Promise.reject(err);
});

const responseInterceptor = axios.interceptors.response.use(response => {
  const type = response.headers['content-type']
  if (type.includes('json'))
    return response.data
  else
    return response

}, error => {
  const originalConfig = error.config;

  if (error.response.status === 401) {
    if (isExpiredTokenError(error.response.data) && !originalConfig._retry) {
      refreshExpiredToken(originalConfig)
    } else {
      store.dispatch('auth/logout', { error: i18n.t('errors.something_went_wrong') })
      return Promise.reject(error);
    }
  }
});

export default function setup() {
  requestInterceptor
  responseInterceptor
}

users.service.js

import { axiosFetcher } from '@/helpers';

export const usersService = {
  retrieveUsers,
}

function retrieveUsers(amount) {
  const requestOptions = {
    method: 'POST',
    data: {
      amount
    },
  };

  return axiosFetcher(`/users`, requestOptions)
    .then((response) => {
      return response['data']
    }, (error) => {
      return error
    })
}

vuex 模块 users.js

import { usersService } from '@/services'

const getDefaultState = () => {
  return { users: [], error: null }
}
const state = getDefaultState()

const actions = {
  retrieveUsers({ commit }) {

    usersService.retrieveUsers()
      .then(
        (response) => {
          if (response.isAxiosError) {
            commit('requestUsersFailure', response.message)
          } else {
            commit('requestUsersSuccess', response)
          }
        }
      )
  },
}

const mutations = {
  requestUsersFailure(state, error) {
    state.error = error
  },
  requestUsersSuccess(state, users) {
    state.users = users
  },
}

const getters = {}

export const users = {
  namespaced: true,
  state,
  actions,
  mutations,
  getters,
}

我打电话this.$store.commit('users/retrieveUsers')

标签: vuejs2axiosjwtvuex

解决方案


推荐阅读