前端
Remix Antd Admin 是一个全站项目,目的是在一个项目里面完成一个较大的项目。前端部分在 React Router 中需要注意一下内容:
不是 SPA 模式
本质上 React Router 不是一个 SPA
模式,而是 Client Only Client
渲染。
这样做的好处是走的 SSR 模式,在需要 SSR 渲染地方可以直接使用 SSR 渲染。
API
Remix Antd Admin 遵循传统前端的 API 数据获取方式,使用 axios 获取。
由于使用了 双 Token 的机制,我们对 Axios 进行了封装:
ts
import axios from "axios";
import { simpleStorage } from "./simpleStorage";
const api = axios.create({
baseURL: "/api/v1",
timeout: 10000,
headers: {
"Content-Type": "application/json",
},
});
// 请求拦截器
api.interceptors.request.use(
(config) => {
// 在发送请求之前处理(如添加 token)
const token = localStorage.getItem("token");
if (token) {
config.headers["Authorization"] = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
// 响应拦截器
api.interceptors.response.use(
async (response) => {
const result = response.data;
if (needRefreshToken(result)) {
// 需要刷新 token
const refreshResponse: any = await api.post("/auth/refresh_token", {
refresh_token: simpleStorage.getRefreshToken(),
});
console.log("refreshResponse", refreshResponse);
if (refreshResponse && refreshResponse.code === 0) {
// 刷新成功,重新请求
simpleStorage.setToken(refreshResponse.data.token);
simpleStorage.setRefreshToken(refreshResponse.data.refresh_token);
response.config.headers["Authorization"] =
`Bearer ${refreshResponse.data.token}`;
return await api.request(response.config);
} else {
// 刷新失败,跳转到登录页
window.location.href = "/login";
}
}
// 对响应数据做处理(比如统一的错误处理)
return response.data; // 只返回数据,去掉不必要的包装
},
async (error) => {
if (error.response.status === 401) {
// 跳转到登录页
window.location.href = "/login";
}
// 统一的错误处理
if (error.response) {
console.error("Response Error:", error.response.data);
} else if (error.request) {
// 请求被发出去,但没有响应
console.error("Request Error:", error.request);
} else {
// 其他错误
console.error("Error:", error.message);
}
return Promise.reject(error);
},
);
function needRefreshToken(result: any) {
if (
result.code === 1 &&
result.message === `"exp" claim timestamp check failed`
) {
return true;
}
return false;
}
export default api;
- 目前支持拦截请求
- 对于过期的请求会执行 refresh_token 和队列保存,然后重试。