路由拦截
第一步:路由拦截
首先在定义路由的时候就需要多添加一个自定义字段requireAuth,用于判断该路由的访问时候需要登录。如果用户已经登录,则顺利进入路由,否则就进入登录页面。
const routers=[
{
path:'/',
name:'/',
component:Index
},
{
path:'/index',
name:'index',
meta:{
requireAuth:true,//添加该字段,表示进入这个路由是需要登录的。
},
component:index
},
{
path:'/login',
name:'login',
component:Login
},
]
//定义完路由后,我们主要是利用vue-router提供的钩子函数beforeEach()对路由进行判断。
router.beforeEach((to,from,next)=>{
if(to.meta.requireAuth){//判断该路由是否需要登录权限。
if(store.state.token){//通过vuex state获取当前的token是否存在。
next();
}else{
next({
path:'/login',
query:{redirect:to.fullPath}//将跳转的路由path作为参数,登陆成功后跳转到该路由
})
}
}else{
next();
}
})
每个钩子方法接收三个参数:
*to:Route:即将要进入的目标路由对象。
*from:Route:当前导航正要离开的路由。
*next:Function:一定要调用该方法来resolve这个钩子。执行效果依赖next方法的调用参数。
*next();进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是confirmed。
*next(false):中断当前的导航。如果浏览器的URL改变了,那么》URL地址会重置到from路由对应的地址。(可能是用户手动或者浏览器后退按钮)
*next(‘/’)或则next({path:’/’}):跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
确保要调用next方法,否则钩子就不会被resolved。
其中,to.meta中是我们自定义的数据,其中就包括我们刚刚定义的requireAuth字段。通过这个字段来判断该路由是否需要登录权限。需要的话,同时当前应用不存在token,则跳转到登录页面,进行登录。登陆成功后跳转到目标路由。
登录拦截到这里就结束了码?并没有。这种方式只是简单的前端路由控制,并不能真正的阻止用户访问需要登陆权限的路由。还有一种情况是:当前token失效了,但是token依然保存在本地。这时候你去访问需要登陆权限的路由时,实际上应该让用户重新登录。
这时候就需要结合http拦截器+后端接口返回的http状态码来判断。
第二步:
要想统一处理http请求和响应,就得用axios的拦截器。通过配置http response inteceptor,当后端接口返回401,让用户重新登录。
//http request拦截器。
axios.interceptors.request.use(
config=>{
if(store.state.token){
config.headers.Authorization = `token${store.state.token}`;
}
return config;
},
err=>{
return Promise.reject(err);
}
);
//http response拦截器
axios.interceptors.response.use(
response=>{
return response;
}
error=>{
if(error.response){
switch(error.response.status){
case 401:
//返回401清楚token信息并跳转到登陆页面
store.commit(types.LOGOUT);
router.replace({
path:'/login',
query:{redirect:router.currentRoute.fullPath}
})
}
}
return Promise.reject(err.response.data)//返回接口返回的错误信息。
}
)
补充一个最全的axios的配置增加了get和post的方法封装,因为post方法传参总是需要qs来序列化请求参数。
//请求拦截、相应拦截、错误统一处理。
import axios from 'axios';
import QS from 'qs';
import store from '../store/index';
//环境的切换
if(process.env.NODE_ENV == 'development'){
axios.defaults.baseUrl = '/api';
}else if(process.env.NODE_ENV == 'debug'){
axios.de
faluts.baseURL = '';
}else if(process.env.NODE_ENV == 'production'){
axios.defaults.baseURL= 'http://api.123dailu.com/';
}
//请求超时时间
axios.defaults.timeout = 10000;
//post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
//请求拦截器
axios.interceptors.request.use(
config=>{
//每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了。
//即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断。
const token = store.state.toekn;
token && (config.headers.Authorization = toekn);
return config;
},
err =>{
return Promise.error(err);
}
)
//响应拦截器
axios.inteceptors.response.use(
respones=>{
if(response.status == 200){
return Promise.resolve(response);
}else{
return Promise.reject(response);
}
},
//服务器状态码不是200的情况
error=>{
if(error.response.status){
switch(error.response.status){
//401:未登录
//未登录则跳转登录页面,并携带当前页面的路径。
//在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path:'/login',
query:{redirect:router.currentRoute.fullPath}
});
break;
//登录过期对用户进行提示。
//清除本地token和清空vuex中的token对象。
//跳转登录页面。
case 403:
Toast({
message:'登录过期,请重新登录',
duration:1000,
forbidClick:true
});
//清除token
localStorage.removeItem('token');
store.commit('loginSuccess',null);
//跳转登陆页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面。
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
}
return Promise.reject(error.response);
}
}
)
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export const get =(url, ...params)=>{
return new Promise((resolve, reject) =>{
axios.get(url, {
params: params
})
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export const post = (url,... params) =>{
return new Promise((resolve, reject) => {
axios.post(url, QS.stringify(...params))
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
使用vue-cookies+axios实现登录拦截
1.安装vue-cookies
npm install vue-cookies --save;
2.在登录接口中设定cookies
this.$http.post(global.domin+'/login/check',{
uesrname:this.ruleForm.username,
password:this.ruleForm.password
}).then(function(response){
var dataObj = respones.data;
if(dataObj.code==200){
that.token = dataObj.data.token;
that.$cookies.set('token',that.token,'45d');//第三个参数是过期时间。
}
}).catch(function(error){
console.log(error);
})
3.在main.js中设置拦截器。
//拦截器 每个接口加token
axios.interceptors.request.use(function(config){
if(VueCookies.get('token')){
config.headers.Authorization = String(VueCookies.get('token'))
//具体是什么样的头,和后端匹配。
};
return config;
},function(error){
return Promise.reject(error);
});
//没有就重新登录
axios.interceptors.response.use(function(response){
// console.log(response)
// if(response.data.code == 401) {
// router.replace({
// name: 'login'
// });
// }
return response;
},function(error){
if(error.response.status==401){
router.replace({
name:'login'
})
}
return Promise.reject(error)//用上面的成功的还是下面报错的根据需求。
})