|
|
@@ -1,89 +1,89 @@
|
|
|
import Axios, {
|
|
|
- type AxiosInstance,
|
|
|
- type AxiosRequestConfig,
|
|
|
- type CustomParamsSerializer
|
|
|
+ type AxiosInstance,
|
|
|
+ type AxiosRequestConfig,
|
|
|
+ type CustomParamsSerializer
|
|
|
} from "axios";
|
|
|
import type {
|
|
|
- PureHttpError,
|
|
|
- RequestMethods,
|
|
|
- PureHttpResponse,
|
|
|
- PureHttpRequestConfig,
|
|
|
- FileHttpRequestConfig
|
|
|
+ PureHttpError,
|
|
|
+ RequestMethods,
|
|
|
+ PureHttpResponse,
|
|
|
+ PureHttpRequestConfig,
|
|
|
+ FileHttpRequestConfig
|
|
|
} from "./types.d";
|
|
|
-import {stringify} from "qs";
|
|
|
+import { stringify } from "qs";
|
|
|
import NProgress from "../progress";
|
|
|
-import {getToken, formatToken} from "@/utils/auth";
|
|
|
-import {useUserStoreHook} from "@/store/modules/user";
|
|
|
+import { getToken, formatToken } from "@/utils/auth";
|
|
|
+import { useUserStoreHook } from "@/store/modules/user";
|
|
|
|
|
|
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
|
|
const defaultConfig: AxiosRequestConfig = {
|
|
|
- // 请求超时时间
|
|
|
- timeout: 10000,
|
|
|
- headers: {
|
|
|
- Accept: "application/json, text/plain, */*",
|
|
|
- "Content-Type": "application/json",
|
|
|
- "X-Requested-With": "XMLHttpRequest"
|
|
|
- },
|
|
|
- // 数组格式参数序列化(https://github.com/axios/axios/issues/5142)
|
|
|
- paramsSerializer: {
|
|
|
- serialize: stringify as unknown as CustomParamsSerializer
|
|
|
- }
|
|
|
+ // 请求超时时间
|
|
|
+ timeout: 10000,
|
|
|
+ headers: {
|
|
|
+ Accept: "application/json, text/plain, */*",
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "X-Requested-With": "XMLHttpRequest"
|
|
|
+ },
|
|
|
+ // 数组格式参数序列化(https://github.com/axios/axios/issues/5142)
|
|
|
+ paramsSerializer: {
|
|
|
+ serialize: stringify as unknown as CustomParamsSerializer
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
class PureHttp {
|
|
|
- constructor() {
|
|
|
- this.httpInterceptorsRequest();
|
|
|
- this.httpInterceptorsResponse();
|
|
|
- }
|
|
|
-
|
|
|
- /** `token`过期后,暂存待执行的请求 */
|
|
|
- private static requests = [];
|
|
|
-
|
|
|
- /** 防止重复刷新`token` */
|
|
|
- private static isRefreshing = false;
|
|
|
-
|
|
|
- /** 初始化配置对象 */
|
|
|
- private static initConfig: PureHttpRequestConfig = {};
|
|
|
-
|
|
|
- /** 保存当前`Axios`实例对象 */
|
|
|
- private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
|
|
|
-
|
|
|
- /** 重连原始请求 */
|
|
|
- private static retryOriginalRequest(config: PureHttpRequestConfig) {
|
|
|
- return new Promise(resolve => {
|
|
|
- PureHttp.requests.push((token: string) => {
|
|
|
- config.headers["Authorization"] = formatToken(token);
|
|
|
- resolve(config);
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- /** 请求拦截 */
|
|
|
- private httpInterceptorsRequest(): void {
|
|
|
- PureHttp.axiosInstance.interceptors.request.use(
|
|
|
- async (config: PureHttpRequestConfig): Promise<any> => {
|
|
|
- // 开启进度条动画
|
|
|
- NProgress.start();
|
|
|
- // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
|
|
|
- if (typeof config.beforeRequestCallback === "function") {
|
|
|
- config.beforeRequestCallback(config);
|
|
|
- return config;
|
|
|
- }
|
|
|
- if (PureHttp.initConfig.beforeRequestCallback) {
|
|
|
- PureHttp.initConfig.beforeRequestCallback(config);
|
|
|
- return config;
|
|
|
- }
|
|
|
- /** 请求白名单,放置一些不需要`token`的接口(通过设置请求白名单,防止`token`过期后再请求造成的死循环问题) */
|
|
|
- const whiteList = ["/refresh-token", "/login"];
|
|
|
- return whiteList.some(url => config.url.endsWith(url))
|
|
|
- ? config
|
|
|
- : new Promise(resolve => {
|
|
|
- const data = getToken();
|
|
|
- if (data) {
|
|
|
- const now = new Date().getTime();
|
|
|
- const expired = parseInt(data.expires_in) - now <= 0;
|
|
|
- if (expired) {
|
|
|
- /*if (!PureHttp.isRefreshing) {
|
|
|
+ constructor() {
|
|
|
+ this.httpInterceptorsRequest();
|
|
|
+ this.httpInterceptorsResponse();
|
|
|
+ }
|
|
|
+
|
|
|
+ /** `token`过期后,暂存待执行的请求 */
|
|
|
+ private static requests = [];
|
|
|
+
|
|
|
+ /** 防止重复刷新`token` */
|
|
|
+ private static isRefreshing = false;
|
|
|
+
|
|
|
+ /** 初始化配置对象 */
|
|
|
+ private static initConfig: PureHttpRequestConfig = {};
|
|
|
+
|
|
|
+ /** 保存当前`Axios`实例对象 */
|
|
|
+ private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
|
|
|
+
|
|
|
+ /** 重连原始请求 */
|
|
|
+ private static retryOriginalRequest(config: PureHttpRequestConfig) {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ PureHttp.requests.push((token: string) => {
|
|
|
+ config.headers["Authorization"] = formatToken(token);
|
|
|
+ resolve(config);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 请求拦截 */
|
|
|
+ private httpInterceptorsRequest(): void {
|
|
|
+ PureHttp.axiosInstance.interceptors.request.use(
|
|
|
+ async (config: PureHttpRequestConfig): Promise<any> => {
|
|
|
+ // 开启进度条动画
|
|
|
+ NProgress.start();
|
|
|
+ // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
|
|
|
+ if (typeof config.beforeRequestCallback === "function") {
|
|
|
+ config.beforeRequestCallback(config);
|
|
|
+ return config;
|
|
|
+ }
|
|
|
+ if (PureHttp.initConfig.beforeRequestCallback) {
|
|
|
+ PureHttp.initConfig.beforeRequestCallback(config);
|
|
|
+ return config;
|
|
|
+ }
|
|
|
+ /** 请求白名单,放置一些不需要`token`的接口(通过设置请求白名单,防止`token`过期后再请求造成的死循环问题) */
|
|
|
+ const whiteList = ["/refresh-token", "/login"];
|
|
|
+ return whiteList.some(url => config.url.endsWith(url))
|
|
|
+ ? config
|
|
|
+ : new Promise(resolve => {
|
|
|
+ const data = getToken();
|
|
|
+ if (data) {
|
|
|
+ const now = new Date().getTime();
|
|
|
+ const expired = parseInt(data.expires_in) - now <= 0;
|
|
|
+ if (expired) {
|
|
|
+ /*if (!PureHttp.isRefreshing) {
|
|
|
PureHttp.isRefreshing = true;
|
|
|
// token过期刷新
|
|
|
useUserStoreHook()
|
|
|
@@ -98,140 +98,140 @@ class PureHttp {
|
|
|
PureHttp.isRefreshing = false;
|
|
|
});
|
|
|
}*/
|
|
|
- config.headers["authorization"] = formatToken(
|
|
|
- data.access_token
|
|
|
- );
|
|
|
- resolve(config);
|
|
|
- } else {
|
|
|
- config.headers["authorization"] = formatToken(
|
|
|
- data.access_token
|
|
|
- );
|
|
|
- resolve(config);
|
|
|
- }
|
|
|
- } else {
|
|
|
- resolve(config);
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- error => {
|
|
|
- return Promise.reject(error);
|
|
|
- }
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- /** 响应拦截 */
|
|
|
- private httpInterceptorsResponse(): void {
|
|
|
- const instance = PureHttp.axiosInstance;
|
|
|
- instance.interceptors.response.use(
|
|
|
- (response: PureHttpResponse) => {
|
|
|
- const $config = response.config;
|
|
|
- // 关闭进度条动画
|
|
|
- NProgress.done();
|
|
|
- // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
|
|
|
- if (typeof $config.beforeResponseCallback === "function") {
|
|
|
- $config.beforeResponseCallback(response);
|
|
|
- return response.data;
|
|
|
- }
|
|
|
- if (PureHttp.initConfig.beforeResponseCallback) {
|
|
|
- PureHttp.initConfig.beforeResponseCallback(response);
|
|
|
- return response.data;
|
|
|
- }
|
|
|
- if (response.data.code === 401) {
|
|
|
- console.log('用户未登录')
|
|
|
- // 用户未登录
|
|
|
- useUserStoreHook().logOut();
|
|
|
- return Promise.reject(new Error("用户未登录"));
|
|
|
+ config.headers["authorization"] = formatToken(
|
|
|
+ data.access_token
|
|
|
+ );
|
|
|
+ resolve(config);
|
|
|
+ } else {
|
|
|
+ config.headers["authorization"] = formatToken(
|
|
|
+ data.access_token
|
|
|
+ );
|
|
|
+ resolve(config);
|
|
|
}
|
|
|
- return response.data;
|
|
|
- },
|
|
|
- (error: PureHttpError) => {
|
|
|
- const $error = error;
|
|
|
- $error.isCancelRequest = Axios.isCancel($error);
|
|
|
- if ($error.status === 401) {
|
|
|
- console.log('登录状态已过期')
|
|
|
- // 用户未登录
|
|
|
- useUserStoreHook().logOut();
|
|
|
- return Promise.reject(new Error("登录状态已过期"));
|
|
|
- }
|
|
|
- // 关闭进度条动画
|
|
|
- NProgress.done();
|
|
|
- // 所有的响应异常 区分来源为取消请求/非取消请求
|
|
|
- return Promise.reject($error);
|
|
|
- }
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- /** 通用请求工具函数 */
|
|
|
- public request<T>(
|
|
|
- method: RequestMethods,
|
|
|
- url: string,
|
|
|
- param?: AxiosRequestConfig,
|
|
|
- axiosConfig?: PureHttpRequestConfig
|
|
|
- ): Promise<T> {
|
|
|
- const config = {
|
|
|
- method,
|
|
|
- url,
|
|
|
- ...param,
|
|
|
- ...axiosConfig
|
|
|
- } as PureHttpRequestConfig;
|
|
|
-
|
|
|
- // 单独处理自定义请求/响应回调
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- PureHttp.axiosInstance
|
|
|
- .request(config)
|
|
|
- .then((response: undefined) => {
|
|
|
- resolve(response);
|
|
|
- })
|
|
|
- .catch(error => {
|
|
|
- reject(error);
|
|
|
- });
|
|
|
+ } else {
|
|
|
+ resolve(config);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ error => {
|
|
|
+ return Promise.reject(error);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 响应拦截 */
|
|
|
+ private httpInterceptorsResponse(): void {
|
|
|
+ const instance = PureHttp.axiosInstance;
|
|
|
+ instance.interceptors.response.use(
|
|
|
+ (response: PureHttpResponse) => {
|
|
|
+ const $config = response.config;
|
|
|
+ // 关闭进度条动画
|
|
|
+ NProgress.done();
|
|
|
+ // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
|
|
|
+ if (typeof $config.beforeResponseCallback === "function") {
|
|
|
+ $config.beforeResponseCallback(response);
|
|
|
+ return response.data;
|
|
|
+ }
|
|
|
+ if (PureHttp.initConfig.beforeResponseCallback) {
|
|
|
+ PureHttp.initConfig.beforeResponseCallback(response);
|
|
|
+ return response.data;
|
|
|
+ }
|
|
|
+ if (response.data.code === 401) {
|
|
|
+ console.log("用户未登录");
|
|
|
+ // 用户未登录
|
|
|
+ useUserStoreHook().logOut();
|
|
|
+ return Promise.reject(new Error("用户未登录"));
|
|
|
+ }
|
|
|
+ return response.data;
|
|
|
+ },
|
|
|
+ (error: PureHttpError) => {
|
|
|
+ const $error = error;
|
|
|
+ $error.isCancelRequest = Axios.isCancel($error);
|
|
|
+ if ($error.status === 401) {
|
|
|
+ console.log("登录状态已过期");
|
|
|
+ // 用户未登录
|
|
|
+ useUserStoreHook().logOut();
|
|
|
+ return Promise.reject(new Error("登录状态已过期"));
|
|
|
+ }
|
|
|
+ // 关闭进度条动画
|
|
|
+ NProgress.done();
|
|
|
+ // 所有的响应异常 区分来源为取消请求/非取消请求
|
|
|
+ return Promise.reject($error);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 通用请求工具函数 */
|
|
|
+ public request<T>(
|
|
|
+ method: RequestMethods,
|
|
|
+ url: string,
|
|
|
+ param?: AxiosRequestConfig,
|
|
|
+ axiosConfig?: PureHttpRequestConfig
|
|
|
+ ): Promise<T> {
|
|
|
+ const config = {
|
|
|
+ method,
|
|
|
+ url,
|
|
|
+ ...param,
|
|
|
+ ...axiosConfig
|
|
|
+ } as PureHttpRequestConfig;
|
|
|
+
|
|
|
+ // 单独处理自定义请求/响应回调
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ PureHttp.axiosInstance
|
|
|
+ .request(config)
|
|
|
+ .then((response: undefined) => {
|
|
|
+ resolve(response);
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ reject(error);
|
|
|
});
|
|
|
- }
|
|
|
-
|
|
|
- /** 单独抽离的`post`工具函数 */
|
|
|
- public post<T, P>(
|
|
|
- url: string,
|
|
|
- params?: AxiosRequestConfig<P>,
|
|
|
- config?: PureHttpRequestConfig
|
|
|
- ): Promise<T> {
|
|
|
- return this.request<T>("post", url, params, config);
|
|
|
- }
|
|
|
-
|
|
|
- /** 单独抽离的`get`工具函数 */
|
|
|
- public get<T, P>(
|
|
|
- url: string,
|
|
|
- params?: AxiosRequestConfig<P>,
|
|
|
- config?: PureHttpRequestConfig
|
|
|
- ): Promise<T> {
|
|
|
- return this.request<T>("get", url, params, config);
|
|
|
- }
|
|
|
-
|
|
|
- /** 单独抽离的`put`工具函数 */
|
|
|
- public put<T, P>(
|
|
|
- url: string,
|
|
|
- params?: AxiosRequestConfig<P>,
|
|
|
- config?: PureHttpRequestConfig
|
|
|
- ): Promise<T> {
|
|
|
- return this.request<T>("put", url, params, config);
|
|
|
- }
|
|
|
-
|
|
|
- /* ----------------------------------- 导出封装 ----------------------------------- */
|
|
|
-
|
|
|
- public postExport<T, P>(
|
|
|
- url: string,
|
|
|
- params?: AxiosRequestConfig<P>,
|
|
|
- config?: FileHttpRequestConfig
|
|
|
- ): Promise<T> {
|
|
|
- const exportConfig = {
|
|
|
- responseType: "blob",
|
|
|
- ...params,
|
|
|
- ...config
|
|
|
- } as PureHttpRequestConfig;
|
|
|
-
|
|
|
- return this.request<T>("post", url, exportConfig);
|
|
|
- }
|
|
|
-
|
|
|
- /* ------------------------------------------------------------------------------- */
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 单独抽离的`post`工具函数 */
|
|
|
+ public post<T, P>(
|
|
|
+ url: string,
|
|
|
+ params?: AxiosRequestConfig<P>,
|
|
|
+ config?: PureHttpRequestConfig
|
|
|
+ ): Promise<T> {
|
|
|
+ return this.request<T>("post", url, params, config);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 单独抽离的`get`工具函数 */
|
|
|
+ public get<T, P>(
|
|
|
+ url: string,
|
|
|
+ params?: AxiosRequestConfig<P>,
|
|
|
+ config?: PureHttpRequestConfig
|
|
|
+ ): Promise<T> {
|
|
|
+ return this.request<T>("get", url, params, config);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 单独抽离的`put`工具函数 */
|
|
|
+ public put<T, P>(
|
|
|
+ url: string,
|
|
|
+ params?: AxiosRequestConfig<P>,
|
|
|
+ config?: PureHttpRequestConfig
|
|
|
+ ): Promise<T> {
|
|
|
+ return this.request<T>("put", url, params, config);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ----------------------------------- 导出封装 ----------------------------------- */
|
|
|
+
|
|
|
+ public postExport<T, P>(
|
|
|
+ url: string,
|
|
|
+ params?: AxiosRequestConfig<P>,
|
|
|
+ config?: FileHttpRequestConfig
|
|
|
+ ): Promise<T> {
|
|
|
+ const exportConfig = {
|
|
|
+ responseType: "blob",
|
|
|
+ ...params,
|
|
|
+ ...config
|
|
|
+ } as PureHttpRequestConfig;
|
|
|
+
|
|
|
+ return this.request<T>("post", url, exportConfig);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ------------------------------------------------------------------------------- */
|
|
|
}
|
|
|
|
|
|
export const http = new PureHttp();
|