【Vue框架】用户和请求

前言

在上一篇 【Vue框架】Vuex状态管理 针对Vuex状态管理以getters.js进行说明,没有对其中state引入的对象进行详细介绍,因为整体都比较简单,也就不对全部做详细介绍了;但其中的user.js涉及到获取用户的信息、前后端请求的token和cookies,因此,这里专门以modules\user.js为头,找到它相关的内容,在从下往上看。

✨该内容个人感觉有点小绕,先整理出了需要看的文件,以及它们间提供方法的关系:
在这里插入图片描述

1、utils\auth.js✨

import Cookies from 'js-cookie'是node_modules里面的方法,这里就不做深入的研究了。

import Cookies from 'js-cookie'

// 用于存储表示用户令牌的键名,cookies中携带token用的key
const TokenKey = 'Admin-Token'✨✨

// 用于从浏览器的 Cookie 中获取用户令牌
export function getToken() {
  // 以获取浏览器 Cookie 中 `TokenKey` 对应的值
  return Cookies.get(TokenKey)
}

// 用于将用户令牌存储到浏览器的 Cookie 中
export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

// 用于从浏览器的 Cookie 中移除用户令牌
export function removeToken() {
  return Cookies.remove(TokenKey)
}

const TokenKey = 'Admin-Token'就是定义了 前端 向 后端 请求时,请求头中cookie存放token的key。

2、utils\request.js

// 该库用于发送 HTTP 请求
import axios from 'axios'
// 从 `element-ui` 模块中导入了 `MessageBox` 和 `Message`,用于显示弹窗和消息提示
import { MessageBox, Message } from 'element-ui'
// 用于获取应用程序的状态
import store from '@/store'
// 用于获取用户令牌
import { getToken } from '@/utils/auth'

// create an axios instance 用于发送 HTTP 请求
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // 实际HTTP url = base url + 访问后端的接口request url
  withCredentials: true, // send cookies when cross-domain requests 以在跨域请求时发送跨域请求的源信息,包括 Cookies
  timeout: 5000 // request timeout
})

// 通过自定义请求拦截器,可以在每个请求发送前对请求进行一些全局配置或处理。在这里,它用于往请求头中添加认证所需的令牌信息
// request interceptor 通过 `service` 实例的 `interceptors.request` 属性调用了 `use` 方法,添加了请求拦截器。
service.interceptors.request.use(
  config => {
    // do something before request is sent 请求发送前的操作
    // 如果存在 `token`,则将 `token` 添加到请求的自定义请求头中
    if (store.getters.token) {
      // let each request carry token 让每个请求携带令牌
      // ['X-Token'] is a custom headers key 指定了自定义请求头的名称为 `X-Token`
      // please modify it according to the actual situation
      // 这个步骤确保每个请求在发送前都携带了认证所需的令牌信息
      config.headers['X-Token'] = getToken()✨✨
    }
    return config
  },
  // 如果请求拦截器中发生了错误,可以通过错误回调函数捕获并处理
  error => {
    // do something with request error
    // 在这里的错误回调函数中,打印错误信息到控制台
    console.log(error) // for debug
    // 以 `Promise.reject(error)` 的形式将错误传递给下一个捕获错误的处理函数
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code 通过自定义代码确定请求状态
   * Here is just an example
   * You can also judge the status by HTTP Status Code 您也可以通过HTTP状态代码来判断状态
   * 响应对象response作为参数,该对象包含了响应的信息、状态码等
   */
  response => {
    const res = response.data

    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      // 在界面上显示一条消息提示框,`Message` 组件是在全局注册的,所以可以在代码中直接使用
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000 // 消息提示框显示的持续时间为 5 秒(以毫秒为单位)
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          // 通过调用 `store` 对象的 `dispatch` 方法来触发 `user` 模块中 `actions` 方法的 `resetToken` 动作
          store.dispatch('user/resetToken').then(() => {
            location.reload() // 刷新当前页面,以重新加载应用程序
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

// 将service对象作为默认导出
export default service

2.1 baseURL: process.env.VUE_APP_BASE_API

process.env.VUE_APP_BASE_API 是一个使用了 Vue CLI 创建的 Vue 项目中的环境变量。
在 Vue CLI 中,我们可以在项目根目录下的 .env 文件(或者是以 .env. 开头的文件)中定义环境变量。

在这里插入图片描述
具体的配置是在vue.config.js中选择环境,如下图:
在这里插入图片描述
baseURL: process.env.VUE_APP_BASE_API具体的作用:定义一个基本固定的路径,配合后端的接口进行使用。

axios会自动处理基本URL与请求路径的拼接(前端调用的时候,一般是baseURL拼接剩下需要的接口内容)
【下面的例子是,baseURL+完整的api】
eg1. 如果baseURL定义为/abc,后端接口的url应该定义为/user,实际HTTP url是ip/abc/user
eg2. 如果baseURL定义为/abc,后端接口的url应该定义为/abc/user,实际HTTP url是ip/abc/user
eg3. 如果baseURL定义为/abc123,后端接口的url应该定义为/abc/user,实际HTTP url是ip/abc123/abc/user

2.2 为什么这里需要引入store来判断token是否存在?

个人理解
其实直接使用getToken()的方式也可以的,没有太大的区别,因为本来store.getter中存的token也就是调用getToken()获得的。

2.3 config.headers[‘X-Token’] = getToken()

这里的'X-Token'其实就是shiro中的Authorization字段,负责传递token,携带在请求头中。
不像utils\auth.js的const TokenKey = 'Admin-Token'是存在cookie中,然后cookie在请求头中。

2.4 export default service

这里虽然导出的是service,但是在别的地方import时可以从新起名
eg. import request from '@/utils/request'
其中的request就是指这里的service,而这个service其实就是配置过的axios

3、api\user.js

// 看2.3 export default service
import request from '@/utils/request'

export function login(data) {
  // 调用 `request(options)`,其中 `options` 是一个包含请求配置的对象
  return request({
    url: '/user/login', // 这里的url需要和后台的接口对应上
    method: 'post',
    data
  })
}

export function getInfo(token) {
  return request({
    url: '/user/info',
    method: 'get',
    params: { token }
  })
}

export function logout() {
  return request({
    url: '/user/logout',
    method: 'post'
  })
}

request是axios配置后的请求方法,在api文件夹下,主要存放一系列请求后端的方法。

4、modules\user.js

// 注意:在import中导入{ xxx },这里的xxx就是属性,因为是解构式赋值,不加'{}'的就是对象
// 用于处理用户登录、注销和获取用户信息的逻辑
import { login, logout, getInfo } from '@/api/user'
// 用于处理用户令牌(token)的获取、存储和移除操作
import { getToken, setToken, removeToken } from '@/utils/auth'
// 导入 `router` 对象和 `resetRouter` 函数,用于处理路由相关的操作
import router, { resetRouter } from '@/router'

// 定义的状态
const state = {
  // 使用 `getToken` 函数从本地存储中获取用户令牌,并作为初始值赋给 `token` 属性
  token: getToken(),
  // 用于存储用户名
  name: '',
  // 用于存储用户头像的 URL
  avatar: '',
  // 用于存储用户简介信息
  introduction: '',
  // 用于存储用户的角色信息
  roles: []
}

// 用于存储一系列 改变 应用状态的方法
// mutation 的作用是更新 Vuex 中的状态,将 `token` 存储在 Vuex 的状态中,以便其他组件可以访问和使用这个 `token`
const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_INTRODUCTION: (state, introduction) => {
    state.introduction = introduction
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  }
}

// 用于存储一系列 触发改变 应用状态的方法
const actions = {
  // user login
  login({ commit }, userInfo) {
    // 从 `userInfo` 中解构出用户名和密码
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        // 为什么既要存Vuex又存Cookies?为了页面关闭、刷新或重新加载后,可以从cookies中取出用户的token,确保登录状态
        commit('SET_TOKEN', data.token) // 将获取的 `data.token` 提交给 Vuex 的 `SET_TOKEN` mutation
        setToken(data.token) // 将 `token` 存储在Cookies中
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response

        if (!data) {
          reject('Verification failed, please Login again.')
        }

        const { roles, name, avatar, introduction } = data

        // roles must be a non-empty array
        if (!roles || roles.length <= 0) {
          reject('getInfo: roles must be a non-null array!')
        }

        commit('SET_ROLES', roles)
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        commit('SET_INTRODUCTION', introduction)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        commit('SET_TOKEN', '')
        commit('SET_ROLES', [])
        removeToken()
        resetRouter() // 重置路由
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      commit('SET_TOKEN', '')
      commit('SET_ROLES', [])
      removeToken()
      resolve()
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

为什么既要存Vuex又存Cookies?
为了页面关闭、刷新或重新加载后,可以从cookies中取出用户的token,确保登录状态

5、前后端response的内容关系

在utils\request.js和modules\user.js中都出现了responseresponse.data,后端菜鸟和前端小白看到应该都得楞一下,这里用截图来展示。

5.1 utils\request.js

这里的responseresponse.data分别如下图所示
在这里插入图片描述

5.2 modules\user.js

这里的response.data其实就是const { data } = response,如果解构赋值有疑惑可以复习一下
快速复习:【Vue框架】Vuex状态管理 中的 2.2 小结
详细复习: 解构赋值详解(详细解释易懂)
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值