目录
我们希望封装出来的axios模块,至少需要具备一种能力,那就是:根据当前模式的不同,设定不同的BaseUrl,因为通常情况下企业级项目在开发状态和生产状态下它的baseUrl是不同的。
我们可以在项目中创建两个文件:
?.env.development??.env.production?它们分别对应开发状态和生产状态。
我们可以在上面两个文件中分别写入以下代码:
.env.development:
# 标志
ENV = 'development'
# base api
VUE_APP_BASE_API = '/api'
.env.production:
# 标志
ENV = 'production'
# base api
VUE_APP_BASE_API = '/prod-api'
有了这两个文件之后,我们就可以创建对应的 axios模块
创建 utils / request.js,我们在这里配置发送 axios 请求的基本信息,写入如下代码:
import axios from 'axios'
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 5000
})
export default service
这里 process.env.VUE_APP_BASE_API 可以根据当前模式的不同来设定我们前文设置好的 baseURL
有了 axios 模块之后,接下来我们就可以
创建 api 文件夹,我们把所有的接口请求模块都放到这个文件夹里,例如登陆注册是一个模块,请求首页文章信息是一个模块:

创建 sys.js ,我们在这里编写登录的接口请求函数:
import request from '@/utils/request'
/**
* 登录
*/
export const login = data => {
return request({
url: '/sys/login',
method: 'POST',
data
})
}
现在调用这个方法返回的就是一个promise对象
什么是登录请求动作呢,就是我们不想在登陆页面中直接调用接口请求方法,而是想把它封装在vuex的模块里**,**我们在 store 下创建 modules 文件夹,创建 user.js 模块,用于处理所有和用户相关的内容(此处需要使用第三方包
md5)。
modules/user.js:
import { login } from '@/api/sys'
import md5 from 'md5'
export default {
namespaced: true,
state: () => ({}),
mutations: {},
actions: {
login(context, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({
username,
password: md5(password)
})
.then(data => {
resolve()
})
.catch(err => {
reject(err)
})
})
}
}
}
注意:这里的md5是一种加密方法,用于加密密码,同学们可以 npm install 来安装。在user.js的actions中,我们把登录请求的动作封装好了,我们在返回的promise对象中调用接口请求模块 login,然后把参数传递进去,返回的promise实例我们通过 then 和 catch 进行接收。
然后我们还需要在 store的 index.js 中完成注册:
import { createStore } from 'vuex'
import user from './modules/user.js'
export default createStore({
modules: {
user
}
})
我们先看一下登录界面主要逻辑的代码:
...
登录
当点击按钮的时候,我们触发登陆动作,首先要进行表单验证,因为这里用的是 element-plus ,其中的 form 组件有一个 validate 的验证方法可以把表单中的每一项进行验证,那我们如何给这个元素添加方法呢,首先得获取到它的实例对象,在 vue2直接 this.$refs.xxx ,就能获取到,而在 vue3 中我们通过在元素上添加 ref 属性,然后只需要在 setup 中声明一个 ref 值为空且和想绑定的 ref 值相同的值就行。在本例中 ref 值为loginFromRef,那我们就在 setup 中定义loginFromRef 为空,通过loginFromRef.value 就能获取到实例对象。
然后通过 store.dispatch 来调用 user 模块下的 login 登陆方法,然后把表单的内容作为参数传递进去。通过 then 指定成功后的回调,catch 指定失败后的回调。
但是当我们这样做完以后是有问题的,控制台会报错 404 ,该错误表示,我们当前请求的接口不存在。出现这个问题的原因,是因为我们在前面配置环境变量时指定了开发环境下,请求的 BaseUrl 为 /api ,所以我们真实发出的请求为:/api/sys/login。
这样的一个请求会被自动键入到当前前端所在的服务中,所以我们最终就得到了**http://192.168.18.42:8081/api/sys/login**这样的一个请求路径。
而想要处理这个问题,那么可以通过指定的 WebPack DevServer 的形式,代理当前的url请求。而指定这个代理非常简单,是一种近乎固定的配置方案。在 vue.config.js 中,加入以下代码:
module.exports = {
devServer: {
// 配置反向代理
proxy: {
// 当地址中有/api的时候会触发代理机制
'/api': {
// 要代理的服务器地址 这里不用写 api
target: 'https://api.imooc-admin.lgdsunday.club/',
changeOrigin: true // 是否跨域
}
}
},
...
}
重新启动服务,再次进行请求,即可得到返回数据:

在登陆成功后,后台返回给我们的信息一般都有 token ,通常情况下,在获取到 token 之后,我们会把 token 进行缓存,而缓存的方式将会分为两种:
LocalStorageVuex保存在LocalStorage是为了方便实现自动登录功能,保存在vuex中是为了后面在其他位置进行使用,那么下面我们就分别来实现对应的缓存方案。
注意:我们一般会将一个对象存入localstorage中,但是localstorage会自动将对象数据转换成字符串形式,这时候我们可以使用JSON.stringify()这个方法,来将数据转换成JSON字符串存入localstorage存入,当读取的时候再使用JSON.parse()方法读取出来。
创建utils/storage.js文件,封装四个对应方法:
/**
* 存储数据
*/
export const setItem = (key, value) => {
// 将数组、对象类型的数据转化为 JSON 字符串进行存储
if (typeof value === 'object') {
value = JSON.stringify(value)
}
window.localStorage.setItem(key, value)
}
/**
* 获取数据
*/
export const getItem = key => {
const data = window.localStorage.getItem(key)
try {
return JSON.parse(data)
} catch (err) {
return data
}
}
/**
* 删除数据
*/
export const removeItem = key => {
window.localStorage.removeItem(key)
}
/**
* 删除所有数据
*/
export const removeAllItem = key => {
window.localStorage.clear()
}
因为获取的 token 值是一个常量,所以我们单独建一个文件来存储常量,创建constant常量目录constant/index.js:
export const TOKEN = 'token'
在 vuex 的 user 模块下处理 token 的存储:
import { login } from '@/api/sys'
import md5 from 'md5'
import { setItem, getItem } from '@/utils/storage'
import { TOKEN } from '@/constant'
export default {
namespaced: true,
state: () => ({
token: getItem(TOKEN) || ''
}),
mutations: {
setToken(state, token) {
state.token = token
setItem(TOKEN, token)
}
},
actions: {
login(context, userInfo) {
...
.then(data => {
this.commit('user/setToken', data.data.data.token)
resolve()
})
...
})
}
}
}
此时,当点击登陆时,即可把token保存至vuex与localStorage中
在上一小节中,我们保存了服务端返回的 token 。但是有一个地方比较难受,那就是在 vuex 的 user 模块中,我们获取数据端的 token 数据,通过 data.data.data.token 的形式进行获取。
一路的 data,确实让人比较难受,如果有过 axios 拦截器处理经验的同学应该知道,对于这种问题,我们可以通过axios 响应拦截器进行处理。
在utils/request.js中实现以下代码:
import axios from 'axios'
import { ElMessage } from 'element-plus'
...
// 响应拦截器
service.interceptors.response.use(
response => {
const { success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
// 业务错误
ElMessage.error(message) // 提示错误消息
return Promise.reject(new Error(message))
}
},
error => {
// TODO: 将来处理 token 超时问题
ElMessage.error(error.message) // 提示错误信息
return Promise.reject(error)
}
)
export default service
此时,对于 vuex 中的 user 模块就可以进行以下修改了:
this.commit('user/setToken', data.token)
首先我们先去对登录鉴权进行一个定义,什么是登录鉴权呢?
login之外的其他页面。token未过期之前,不允许进入login页面。而想要实现这个功能,那么最好的方式就是通过路由守卫来进行实现。
那么明确好了登录鉴权的概念之后,接下来就可以去实现一下,在路由 index.js 页面进行配置:
// 白名单
const whiteList = ['/login']
/**
* 路由前置守卫
*/
router.beforeEach(async (to, from, next) => {
// 存在 token ,进入主页
if (store.state.user.token) {
if (to.path === '/login') {
next('/')
} else {
next()
}
} else {
// 没有token的情况下,可以进入白名单
if (whiteList.indexOf(to.path) > -1) {
next()
} else {
next('/login')
}
}
})
配置白名单是因为如果他没有 token ,可能是没有登录,也可能页面是 404 或者 401 状态,我们不应该设定只要没 token 都跳转到登录页面。
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦