说明: 登录成功之后服务器会返回两个 `token` 相关的数据
1. token
- 用来做身份认证的,好让服务器知道你是谁,但是token是有有效期的,在本项目中,有效期为 `2小时`
- 每过 2 小时,`token` 会失效,需要重新登录
- 用户视角:操作着页面,突然需要重新登录,用户体验不好
- 模拟 token 失效: 找到 `开发者工具 => Application => localstorage => 对应的 token => 双击 token 的值进行编辑`
2.refresh_token
- `refresh_token` 用于在token过期后,获取新的用户token
- 它的有效期为14天
结论:
为了解决 `token` 每 `2` 小时过期一次的问题:
监听服务器的响应是否出错
判断是否是 toke 失效
* 是:通过 `refresh_token` 获取新的 `token`
* 否:不用理会
1.token失效--------解决方案
一旦 `token` 过期,使用这个过期的 `token` 时,服务器会报错,错误的状态码为: `401`
解决方案(响应拦截器中):
* 判断错误的状态码是否为 `401`
* 如果是 `401` ,根据 `refresh_token` 得到新的 `token`
* 再将原来的 `token` 替换掉
const instance = axios.create({
baseURL: "http://toutiao.itheima.net/",
});
// 再创建一个 axios 的副本(负责更新 token)
const refInstance = axios.create({
baseURL: "http://toutiao.itheima.net/",
});
// 响应拦截器
instance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
console.dir(error);
const status = error.response.status;
if (status === 401) {
console.log(status);
const refresh_token = store.state.token.refresh_token;
console.log(refresh_token);
try {
const res = await refInstance({
url: "/v1_0/authorizations",
method: "PUT",
headers: {
Authorization: `Bearer ${refresh_token}`,
},
});
console.log(res);
store.commit("setToken", {
token: res.data.data.token,
refresh_token: refresh_token,
});
console.log("更新成功");
return instance(error.config);
} catch (e) {
Toast.fail("登录已经过期");
router.push("/login");
return Promise.reject(new Error("refresh_token 已过期"));
}
}
return Promise.reject(error);
}
);
**注意点:**
* 在更新 `token` 时,一定不能使用之前 `instance` 实例来发送请求:
* 原因:它有一个请求拦截器,这个请求拦截器,会将设置好的 `Authorization` 覆盖为失效的 `token`
* 解决方案:再创建一个 `axios` 副本对象,这个副本对象只用来更新 `token`
2.token失效-------无感刷新
* 解决了 `token` 失效之后,页面依旧无法正常请求数据
* 手动刷新页面之后,功能才能正常
* 手动刷新页面用户体验不好
* `token` 更新之后,重新请求之前出错的请求
return instance(error.config);
3.token失效--------解决refresh_token失效
当token和refresh_token全部失效是,跳转到登陆页面,给出失效提示,重新登录。
方法:
* 使用`try catch` 包裹更新 `token`的代码
* 在 `catch` 中跳转到登录页面
try {
const res = await refInstance({
url: "/v1_0/authorizations",
method: "PUT",
headers: {
Authorization: `Bearer ${refresh_token}`,
},
});
console.log(res);
store.commit("setToken", {
token: res.data.data.token,
refresh_token: refresh_token,
});
console.log("更新成功");
return instance(error.config);
} catch (e) {
Toast.fail("登录已经过期");
router.push("/login");
return Promise.reject(new Error("refresh_token 已过期"));
}