401到底是什么原因造成的?来看看吧,看了就会 | 您所在的位置:网站首页 › token到期了会引起什么后果 › 401到底是什么原因造成的?来看看吧,看了就会 |
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,[点击查看活动详情](juejin.cn/post/708080… )。 401问题-背景介绍 有如下两种情况会出现401错误: 未登陆用户做一些需要权限才能做的操作(例如:关注作者),代码会报出401错误。这种情况下,应该让用户回到登陆页。 登录用户的token过期了 ( token会有有效期(具体是多长,是由后端决定)) 401错误的场景401是http的状态码,表示本次请求没有权限; 有如下两种情况会出现401错误: 未登陆用户做一些需要权限才能做的操作(例如:关注作者),network中会提示本次请求是401错误 登录用户的token过期了 理解token过期登陆成功之后,接口会返回一个token值,这个值在后续请求时通过请求头时带上(就像是进入小区门的开门钥匙)。但是,这个值一般会有有效期(具体是多长,是由后端决定),在我们的项目中,这个有效期是2小时。 如果你上午8点登陆成功,到了10:01分,则token就会失效,再去发请求时,就会报401错误。 双token refresh_token和token的作用当用户登陆成功之后,返回的token中有两个值: token: 作用:一般情况下,在访问接口时,需要传入的token值就是它。 有效期:2小时(安全)。 refresh_token 作用: 当token的有效期过了之后,可以使用refresh_token去请求一个特殊接口(这个接口也是后端指定的,明确需要传入refresh_token),并返回一个新的token回来(有效期还是2小时),以替换过期的那个token。 有效期:14天。(最理想的情况下,一次登陆可以持续14天。) 401问题 响应拦截器功能axios中提供了响应拦截器功能:所有从后端回来的响应都会先进入响应拦截器,包括出错的请求中。所以,我们可以在响应拦截器中去写代码来统一解决。 // 添加响应拦截器instance.interceptors.response.use(function (response) { return response}, async function (error) { // 如果发生了错误,判断是否是401 console.dir(error) // 开始处理 return Promise.reject(error)}) 401问题的思路让用户对因token过期产生的401错误无感知 request的响应拦截器中: 对于某次请求A,如果是401错误 (2) 有refresh_token,用refresh_token去请求回新的token (3) 新token请求成功 (4) 更新本地token (5) 再发一次请求A (6) 新token请求失败 携带请求地址,跳转到登陆页没有refresh_token,说明没有登陆 携带请求地址,跳转到登陆页 401问题-代码在src\utils\request.ts中,补充响应拦截器。 由于这里涉及到非组件内路由跳转,所以需要提前封装独立的history 封装独立的history创建文件 src\utils\history.ts import { createBrowserHistory } from 'history'const history = createBrowserHistory()export default history在app.tsx中使用 import history from '@/utils/history'function App () { return ( 补充action在actions/login.ts中,补充一个action用来去做更新token的操作 export function saveToken (token: Token) : LoginAction { // 1. 本地持久化 setToken(token) // 2. 保存token return { type: 'login/token', payload: token }} 核心代码要进行路由跳转,所以要引入/history.js中的history。 在request.ts中,添加响应拦截器 // 添加响应拦截器instance.interceptors.response.use( function (response) { // 对响应数据做点什么 return response }, async function (error: AxiosError) { // 对请求错误做些什么 if (!error.response) { Toast.show('网络异常') return Promise.reject(error) } if (error.response.status !== 401) { Toast.show('后端错误') return Promise.reject(error) } const { refresh_token } = getToken() if (!refresh_token) { // alert('refresh_token') history.replace('/login', { from: history.location.pathname }) Toast.show('登录信息过期') return Promise.reject(error) } try { // 使用refresh_token去换取新token // 使用 axios 来发送请求 const res = await axios.put(`${baseURL}authorizations`, null, { headers: { Authorization: `Bearer ${refresh_token}` } }) // setToken(tokens) store.dispatch(saveToken({ token: res.data.data, refresh_token })) return instance(error.config) } catch (e) { // setToken(tokens) store.dispatch(logout()) history.replace('/login', { from: history.location.pathname }) return Promise.reject(e) } })注意: 响应拦截器要加在axios实例 request上。 用refresh_token请求新token时,要用axios,不要用实例request 得到新token之后,再发请求时,要用request实例 |
CopyRight 2018-2019 实验室设备网 版权所有 |