封装Vuex的登录Action并处理token
目标在vuex中封装登录的action,并处理token
在这个小节中,我们将在vuex中加入对于用户的登录的处理
在Vuex中对token进行管理
在传统模式中,我们登录的逻辑很简单,如图
上图中,组件直接和接口打交道,这并没有什么问题,但是对于用户token这一高频使用的
钥匙,我们需要让vuex来介入,将用户的token状态共享,更方便的读取,如图
实现store/modules/user.js基本配置
// 状态
const state = {}
// 修改状态
const mutations = {}
// 执行异步
const actions = {}
export default {
namespaced: true,
state,
mutations,
actions
}
设置token的共享状态
const state = {
token: null
}
我们需要知道,
钥匙不能每次都通过登录获取,我们可以将token放置到本地的缓存中
在utils/auth.js中,基础模板已经为我们提供了获取token,设置token,删除token的方法,可以直接使用
只需要将存储的key放置成特定值即可
import Cookies from 'js-cookie'
const TokenKey = 'hrsaas-ihrm-token' // 设定一个独一无二的key
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
初始化token状态 - store/modules/user.js
import { getToken, setToken, removeToken } from '@/utils/auth'
// 状态
// 初始化的时候从缓存中读取状态 并赋值到初始化的状态上
// Vuex的持久化 如何实现 ? Vuex和前端缓存相结合
const state = {
token: getToken() // 设置token初始状态 token持久化 => 放到缓存中
}
提供修改token的mutations
// 修改状态
const mutations = {
// 设置token
setToken(state, token) {
state.token = token // 设置token 只是修改state的数据 123 =》 1234
// vuex变化 => 缓存数据
setToken(token) // vuex和 缓存数据的同步
},
// 删除缓存
removeToken(state) {
state.token = null // 删除vuex的token
removeToken() // 先清除 vuex 再清除缓存 vuex和 缓存数据的同步
}
}
封装登录的Action
封装登录的action
登录action要做的事情,
调用登录接口,成功后设置token到vuex,失败则返回失败
// 执行异步
const actions = {
// 定义login action 也需要参数 调用action时 传递过来的参数
async login(context, data) {
const result = await login(data) // 实际上就是一个promise result就是执行的结果
// axios默认给数据加了一层data
if (result.data.success) {
// 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的
// 现在有用户token
// actions 修改state 必须通过mutations
context.commit('setToken', result.data.data)
}
}
}
上述代码中,我们使用了
async/await语法,如果用then语法也是可以的
// 为什么async/await 不用返回new Promise,因为 async函数本身就是 Promise,promise的值返回的值
login(context, data) {
return new Promise(function(resolve) {
login(data).then(result => {
if (result.data.success) {
context.commit('setToken', result.data.data) // 提交mutations设置token
resolve() // 表示执行成功了
}
})
})
}
以上两种写法都是OK的,我们在项目研发过程中,尽可能的采用前一种
除此之外,为了更好的让其他模块和组件更好的获取token数据,我们可以在store/getters.js中将token值作为公共的访问属性放出
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token // 在根级的getters上 开发子模块的属性给别人看 给别人用
}
export default getters
提交代码
通过本节内容,我们要掌握在Vuex中如何来管理共享状态
本节任务:封装Vuex的登录Action并处理token
request中环境变量和异常的处理
目标设置request环境变量和异常处理
区分axios在不同环境中的请求基础地址
为什么会有环境变量之分? 如图
从上图可以看出,开发环境实际上就是在自己的本地开发或者要求不那么高的环境,但是一旦进入生产,就是
真实的数据。 拿银行作比喻,如果你在开发环境拿生产环境的接口做测试,银行系统就会发生很大的风险。
前端主要区分两个环境,开发环境,生产环境
也就是两个环境发出的请求地址是不同的,用什么区分呢?
环境变量
$ process.env.NODE_ENV # 当为production时为生产环境 为development时为开发环境
环境文件
我们可以在.env.development和.env.production定义变量,变量自动就为当前环境的值
基础模板在以上文件定义了变量VUE_APP_BASE_API,该变量可以作为axios请求的baseURL
我们会发现,在模板中,两个值分别为/dev-api和/prod-api
但是我们的开发环境代理是/api,所以可以统一下
# 开发环境的基础地址和代理对应 不需要引号 VUE_APP_BASE_API = /api
# 这里配置了/api,意味着需要在Nginx服务器上为该服务配置 nginx的反向代理对应/prod-api的地址 不需要引号 VUE_APP_BASE_API = /prod-api
本节注意:我们这里生产环境和开发环境设置了不同的值,后续我们还会在生产环境部署的时候,去配置该值所对应的反向代理,反向代理指向哪个地址,完全由我们自己决定,不会和开发环境冲突
在request中设置baseUrl
const service = axios.create({
// 如果执行 npm run dev 值为 /api 正确 /api 这个代理只是给开发环境配置的代理
// 如果执行 npm run build 值为 /prod-api 没关系 运维应该在上线的时候 给你配置上 /prod-api的代理
baseURL: process.env.VUE_APP_BASE_API, // 设置axios请求的基础的基础地址
timeout: 5000 // 定义5秒超时
}) // 创建一个axios的实例
处理axios的响应拦截器
OK,除此之外,axios返回的数据中默认增加了一层
data的包裹,我们需要在这里处理下
并且,人资项目的接口,如果执行失败,只是设置了
success为false,并没有reject,我们需要一并处理下
处理逻辑如图
// 响应拦截器
service.interceptors.response.use(response => {
// axios默认加了一层data
const { success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
// 业务已经错误了 还能进then ? 不能 ! 应该进catch
Message.error(message) // 提示错误消息
return Promise.reject(new Error(message))
}
}, error => {
Message.error(error.message) // 提示错误信息
return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入 catch
})
既然在request中已经默认去除了一层data的外衣,所以我们也将上节login的action进行一下改动
处理登录的返回结构问题
async login(context, data) {
// 经过响应拦截器的处理之后 这里的result实际上就是 token
const result = await login(data) // 实际上就是一个promise result就是执行的结果
// axios默认给数据加了一层data
// 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的
// 现在有用户token
// actions 修改state 必须通过mutations
context.commit('setToken', result)
}
提交代码
本节任务: 完成request环境变量和异常的处理
登录页面调用登录action,处理异常
目标 调用vuex中的登录action,并跳转到主页
按照如图的业务逻辑,把剩下的内容在登录页面引入
引入actions辅助函数
import { mapActions } from 'vuex' // 引入vuex的辅助函数
引入action方法
此处,我们采用直接引入模块action的方式,后面我们采用分模块的引用方式
methods: {
...mapActions(['user/login'])
}
调用登录
this.$refs.loginForm.validate(async isOK => {
if (isOK) {
try {
this.loading = true
// 只有校验通过了 我们才去调用action
await this['user/login'](this.loginForm)
// 应该登录成功之后
// async标记的函数实际上一个promise对象
// await下面的代码 都是成功执行的代码
this.$router.push('/')
} catch (error) {
console.log(error)
} finally {
// 不论执行try 还是catch 都去关闭转圈
this.loading = false
}
}
})
提交代码
本节注意:我们调用的是Vuex中子模块的action,该模块我们进行了namespaced: true,所以引用aciton时需要带上user/, 并且在使用该方法时,直接使用 this['user/login'], 使用this.user/login 语法是错误的
本文档详细介绍了如何在Vuex中封装登录Action并处理token,包括在Vuex中设置token的共享状态,以及在不同环境中处理axios的请求基础地址和响应拦截器。同时,讨论了登录页面如何调用登录Action并处理异常。
548

被折叠的 条评论
为什么被折叠?



