React中从local storage获取token传入axios请求的最佳实践是什么?
推荐实现方案
以下是从可维护性、复用性角度出发的优化方案,按优先级排列:
1. 第一步:抽离公共工具方法解决重复代码问题
把重复的getTokenFromLocalStorage方法单独抽离为公共工具函数,存放在src/utils/auth.js这类公共工具目录下,所有需要的服务直接导入使用即可:
// src/utils/auth.js export const getTokenFromLocalStorage = () => { try { const token = localStorage.getItem("token"); console.log("the token is -> " + token); return token ?? undefined; } catch(err) { return undefined; } }
之后在AuthService、TicketService里直接导入这个函数使用,不用每个类都单独实现一遍。
2. 第二步:用axios拦截器统一注入token,彻底避免每个请求单独配置header
创建全局通用的自定义axios实例,统一配置baseURL、请求拦截器自动注入token,不用每个接口请求都手动写header配置:
// src/utils/request.js import axios from 'axios' import { getTokenFromLocalStorage } from './auth' const request = axios.create({ baseURL: API_BASE_URL, timeout: 10000 }) // 请求拦截器:自动注入token request.interceptors.request.use( config => { const token = getTokenFromLocalStorage() if (token) { // 适配不同接口的header要求 if (config.url === '/authenticate') { config.headers.token = token } else { config.headers.Authorization = `Bearer ${token}` } } return config }, error => { return Promise.reject(error) } ) // 还可以加响应拦截器统一处理token过期、401权限不足的情况,自动跳转到登录页 request.interceptors.response.use( response => response, error => { if (error.response?.status === 401) { window.location.href = '/login' } return Promise.reject(error) } ) export default request
之后两个Service里直接用这个封装好的axios实例发请求即可,不用再处理token和header:
// AuthService 简化后 import request from '@/utils/request' export const validateToken = () => { return request.get("/authenticate") .catch((error) => { console.log("failed to validate token" + error); return null; }); } // TicketService 简化后 import request from '@/utils/request' export const getTickets = () => { console.log("getting tickets!"); console.log("Environment variable: " + process.env.NODE_ENV); return request.get("/tickets") .catch((error) => { console.log("failed to get tickets" + error); }); }
3. 第三步:统一鉴权逻辑,避免每个组件单独写校验
如果项目用的是React Router,可以用路由守卫/高阶组件统一包裹需要鉴权的路由,所有需要登录的页面都会自动走token校验,不用每个组件的componentDidMount里都重复写校验逻辑:
// 鉴权高阶组件示例 import { useEffect } from 'react' import { validateToken } from '@/services/AuthService' const withAuth = (Component) => { return (props) => { useEffect(() => { const checkAuth = async () => { const res = await validateToken() const token = localStorage.getItem('token') if (!res || !token) { props.history.push('/login') } } checkAuth() }, [props.history]) return <Component {...props} /> } } // 路由配置时直接包裹需要鉴权的组件即可 <Route path="/tickets" component={withAuth(TicketsComponent)} />
原有代码的小问题修复
- 原来的
then("did it")、then("yessssss")写法是错误的,then的参数需要是函数,否则会直接透传上一步的返回值,没有实际作用,建议删除 - 可以在校验token前先判断本地有没有token,如果没有直接跳登录,不用发无效的校验请求
内容的提问来源于stack exchange,提问作者mcool
相关产品推荐
相关产品推荐

