client.ts
2.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import axios, { AxiosError } from "axios";
import { message } from "antd";
const TOKEN_KEY = "xly.access";
export function getToken(): string | null {
return sessionStorage.getItem(TOKEN_KEY);
}
export function setToken(t: string): void {
sessionStorage.setItem(TOKEN_KEY, t);
}
export function clearToken(): void {
sessionStorage.removeItem(TOKEN_KEY);
}
export interface ApiEnvelope<T = unknown> {
code: number;
msg: string;
data: T;
}
export class ApiError extends Error {
code: number;
constructor(code: number, msg: string) {
super(msg);
this.code = code;
}
}
export const http = axios.create({
baseURL: "/api",
timeout: 15000,
headers: { "Content-Type": "application/json" },
});
http.interceptors.request.use((config) => {
const tok = getToken();
if (tok) {
config.headers = config.headers ?? {};
(config.headers as Record<string, string>).Authorization = `Bearer ${tok}`;
}
return config;
});
http.interceptors.response.use(
(response) => {
const env = response.data as ApiEnvelope;
if (env && typeof env.code === "number" && env.code !== 0) {
message.error(env.msg || "请求失败");
throw new ApiError(env.code, env.msg || "请求失败");
}
return response;
},
(err: AxiosError<ApiEnvelope>) => {
if (err.response?.status === 401) {
clearToken();
// Redirect to /login. Use location to avoid coupling axios with React Router.
if (window.location.pathname !== "/login") {
window.location.href = "/login";
}
return Promise.reject(new ApiError(401, "未登录或会话过期"));
}
const env = err.response?.data;
const msg = env?.msg || err.message || "网络错误";
message.error(msg);
return Promise.reject(new ApiError(env?.code ?? -1, msg));
}
);
// Convenience: call http and unwrap envelope to data.
export async function request<T = unknown>(
config: Parameters<typeof http.request>[0]
): Promise<T> {
const resp = await http.request<ApiEnvelope<T>>(config);
return resp.data.data;
}