1 准备工作
1.1 重构src\store\index.js
import {
createStore
} from 'vuex';
export default createStore({
state: {
//通过该全局变量,获取全局化存储的1个指定用户的令牌字符串。
token: localStorage.getItem('Token') ? localStorage.getItem('Token') : '',
//通过该全局变量,获取全局化存储的1个指定用户的1个指定令牌字符串的过期时间。
expiresIn: localStorage.getItem('TokenExpiresIn') ? localStorage.getItem('TokenExpiresIn') : '',
},
getters: {},
mutations: {
//通过该方法把“TokenJwt”字符串,进行全局存储。
saveToken: function(state, data) {
state.token = data;
localStorage.setItem("Token", data);
},
//通过该方法把1个指定用户的1个指定令牌字符串的过期时间进行全局化存储。
saveExpiresIn: function(state, data) {
state.token = data;
localStorage.setItem("TokenExpiresIn", data);
},
},
actions: {},
modules: {}
})
1.2 重构src\views\LoginView.vue
<template>
<el-form :model="formLogin" label-position="left" label-width="0px" class="demo-ruleForm login-container">
<h3 class="title">系统登录</h3>
<el-form-item prop="account">
<el-input type="text" v-model="formLogin.account" auto-complete="off" placeholder="账号"></el-input>
</el-form-item>
<el-form-item prop="checkPass">
<el-input v-model="formLogin.checkPass" auto-complete="off" show-password placeholder="密码"></el-input>
</el-form-item>
<el-form-item style="width:100%;">
<el-button type="primary" style="width:100%;" @click="submitLogin">
登录
</el-button>
</el-form-item>
</el-form>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
formLogin: {
account: 'admin@yourStore.com',
checkPass: '1',
},
};
},
methods: {
async submitLogin() {
let loginParams = {
email: this.formLogin.account,
password: this.formLogin.checkPass
};
let res = await axios.post('https://localhost:7239/Customer/Login', JSON.stringify(loginParams));
console.log(res);
let userToken = 'Bearer ' + res.data.response.token;
this.$store.commit("saveToken", userToken);
//把1个指定用户的1个指定令牌字符串的过期时间进行全局化存储。
var curTime = new Date();
var expiresIn = new Date(curTime.setSeconds(curTime.getSeconds() + res.data.response.expiresIn));
this.$store.commit("saveExpiresIn", expiresIn);
if (res.status == 200) {
let token = localStorage.getItem('Token');
if (token === null || token === '') {
await this.$router.replace(this.$route.query.redirect ? this.$route.query.redirect :"/Login");
}
await this.$router.replace(this.$route.query.redirect ? this.$route.query.redirect : "/");
} else {
this.$message.error(res.msg);
}
},
},
mounted() {
//把Token字符串添加到Header拦截守卫。
axios.interceptors.request.use(
config => {
if (localStorage.getItem('Token')) {
config.headers.Authorization = localStorage.getItem('Token');
}
return config;
},
error => {
return Promise.reject(error);
});
},
}
</script>
2 抽离Axios拦截守及其全局变量定义:src\common\http.interceptor.js
import axios from 'axios';
import router from '../router/index'
//实例化拦截守卫实例。
const axiosInterceptor = axios.create({
baseURL: 'https://localhost:7239/', // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
timeout: 60000, // 请求超时时间毫秒
//withCredentials:必须设定为false,或不对“withCredentials”进行设定,则否会出现异常:
//Access to XMLHttpRequest at 'https://localhost:7239/Role/Index' from origin 'http://localhost:8080'
//has been blocked by CORS policy: Response to preflight request doesn't pass access control
//check: The value of the 'Access-Control-Allow-Credentials' header in the response is ''
//which must be 'true' when the request's credentials mode is 'include'.
//The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
withCredentials: false, // 异步请求携带cookie
headers: {
'Content-Type': 'application/json',
'token': 'your token',
'X-Requested-With': 'XMLHttpRequest',
},
});
//通过拦截守卫实例,把Token令牌字符串添加到Header字典实例中,从而授权指定用户有权访问指定页面。
axiosInterceptor.interceptors.request.use(
config => {
if (localStorage.getItem('Token')) {
config.headers.Authorization = localStorage.getItem('Token');
}
return config;
},
error => {
return Promise.reject(error);
}
);
//通过拦截守卫实例在错误产生时获取对应的状态码,并根据对应状态码跳转到指定页。
axiosInterceptor.interceptors.response.use(
(config) => {
return config;
},
async error => {
let statusErrorInfo = {
success: false,
message: "错误"
};
if (error.response?.status === 400) {
statusErrorInfo.message =
`${error.response?.status}:由于前端所发送的请求中有语法错误,服务器(后)端不能解析该请求或解析请求时产生错误,从而导致服务器(后)端已处理前端所发送的请求失败。`;
console.log(statusErrorInfo.message);
return await router.replace(router.redirect ? router.redirect : "/Login");
} else if (error.response?.status === 401) {
statusErrorInfo.message =
`${error.response?.status}:由于用户未执行登录操作,所以没有权限访问当前页面。`;
var curTime = new Date();
var expiresIn = new Date(Date.parse(window.localStorage.expiresIn));
//如果1个指定用户的1个指定令牌字符串已经过期。
if (curTime > expiresIn) {
statusErrorInfo.message =
`${error.response?.status}:由于指定用户的Token令牌字符串已经过期,所以没有权限访问当前页面。`;
}
console.log(statusErrorInfo.message);
return await router.replace(router.redirect ? router.redirect : "/Login");
} else if (error.response?.status === 403) {
statusErrorInfo.message =
`${error.response?.status}:该指定用户虽然已经执行登录操作,但该用户没有访问当前页面的权限。`;
console.log(statusErrorInfo.message);
return await router.replace(router.redirect ? router.redirect : "/Login");
} else if (error.response?.status === 422) {
statusErrorInfo.message =
`${error.response?.status}:由于前端所发送的请求中所携带的参数实例与服务器(后)端中对应的API方法所需要的参数实例不匹配,从而导致服务器(后)端已处理前端所发送的请求失败(response)`;
console.log(statusErrorInfo.message);
return await router.replace(router.redirect ? router.redirect : "/Login");
} else if (error.response.status >= 500) {
statusErrorInfo.message =
`${error.response?.status}:服务器(后)端中对应的API方法在处理前端所发送的请求时产生错误,服务器(后)端API方法未能完成前端所发送的请求,从而导致服务器(后)端已处理前端所发送的请求失败(response)。`;
console.log(statusErrorInfo.message);
return await router.replace(router.redirect ? router.redirect : "/Login");
}
if (error.response.status >= 505) {
statusErrorInfo.message =
`${error.response?.status}:由于服务器(后)端不支持前端所发送的请求的HTTP协议的版本,从而导致服务器(后)端已处理前端所发送的请求失败(response)。`;
console.log(statusErrorInfo.message);
return await router.replace(router.redirect ? router.redirect : "/Login");
}
return Promise.reject(error);
}
);
export default axiosInterceptor
3 重构端管理首页:src\views\WelcomeView.vue
<template>
<h1>WelcomeView-----Amin</h1>
</template>
<script>
import axiosInstance from '../common/http.interceptor.js';
export default {
data() {
return {};
},
methods: {
async getHomeAdminIndex() {
let res = await axiosInstance.get('HomeAdmin/Index');
console.log(res.data);
},
},
async mounted() {
await this.getHomeAdminIndex();
},
};
</script>
<style scoped lang="scss">
</style>
4 调试
对以上功能更为具体实现和注释见:230221_010shopvue(抽离Axios拦截守及其全局变量定义)。