在平时的项目中,做到登陆的一个状态,就会遇到在没有等登陆的情况下不让其访问其它页面,和在token过期的情况下应该要返回login页面的业务问题,这边带大家如何实现这些业务问题,并用发布订阅来来实现在token过期的情况下应该返回login页面的业务问题
一、没有token不让其访问页面
在vue中有路由守卫来实现这个功能,但是在react中是没有路由守卫了,需要自己来写;在react可以使用useNavigate的replace覆盖历史和useEffect来实现
在需要首页的跟目录中写入即可
import React,{useEffect} from 'react'
import {Outlet,useNavigate} from "react-router-dom"
export default function Apps() {
const navigate= useNavigate()
const token =sessionStorage.getItem("token")
useEffect(()=>{
if(!token){
// 当没有token的时候就返回登陆页,并且只执行一次
console.log("请先登陆");
navigate("/login",{replace:true})// replace:true 覆盖历史
}
},[])
// 判断当有token 的时候就进入页面,
if(token){
return (
<>
{/* Outle 显示子路由,在react-router-dom中引入,和vue的<router-view/>一个道理 */}
<Outlet/>
</>
)
}else{
return <></>
}
}
像上面这个样子就可以实现在没有token的情况下不让其访问首页
二、token过期返回login页面
1、首先先创建一个全新的文件夹,写入发布订阅的代码,然后导出
interface IEvents {
[index: string]: Array<Function>;
}
interface IEventBus {
events: IEvents;
on: (key: string, func: Function) => void;
emit: (key: string) => void;
}
// 设计模式是编程思想,跟语言无关
// 原理: 把一些函数,放到一个数组里面,后面需要使用的时候通过数组直接取出,调用
const EventBus: IEventBus = {
events: {},
// 订阅事件的方法
//
on(key: string, func: Function) {
// 使用key对应一个数组,数组里面存着所有的函数
if (!this.events[key]) {
this.events[key] = [];
}
this.events[key].push(func);
},
// 发布事件的方法
emit(key: string) {
this.events[key].forEach((func) => func());
},
};
export default EventBus;
2、在axios拦截器响应错误的地方拿到错误的状态值,然后删除token和订阅一下上面的代码
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"
import EventBus from "../util/EventBus";
const instance: AxiosInstance = axios.create({
baseURL:"http://localhost:8080",
timeout: 5000
});
// 添加请求拦截器
instance.interceptors.request.use(function (config: AxiosRequestConfig<any>) {
let token = sessionStorage.getItem("token") as string
if (token) {
config.headers = config.headers || {}
config.headers["xxx"] = token
}
// 在发送请求之前做些什么
return config;
}, function (error: any) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response: AxiosResponse<any, any>) {
// 对响应数据做点什么
return response.data;
}, function (error: any) {
//这里是响应错误时返回的数据,在这边操作即可
let err=error.response.data.errCode
if(err===1001||err===1002){
// 这里是发布,在相对于的页面里面订阅
sessionStorage.removeItem("token")
EventBus.emit("loginTimeout")
}
// 对响应错误做点什么
return Promise.reject();
});
export default instance
然后来到首页的跟目录页面,在这里订阅
import React,{useEffect} from 'react'
import {Outlet,useNavigate} from "react-router-dom"
import EventBus from "./util/EventBus";
export default function Apps() {
const navigate= useNavigate()
const token =sessionStorage.getItem("token")
useEffect(()=>{
if(!token){
// 当没有token的时候就返回登陆页,并且只执行一次
console.log("请先登陆");
navigate("/login",{replace:true})// replace:true 覆盖历史
}
},[])
//订阅发布的代码
EventBus.on("loginTimeout", function () {
// 如果登录失效 1.弹出提示 2.跳转到login
const.log("登录失效")
navigate("/login", { replace: true });
});
// 判断当有token 的时候就进入页面,
if(token){
return (
<>
{/* Outle 显示子路由,在react-router-dom中引入,和vue的<router-view/>一个道理 */}
<Outlet/>
</>
)
}else{
return <></>
}
}
好了,这样你就已经完成,如有不懂或有不足之处欢迎大家留言讨论