<% const { apiConfig, generateResponses, config } = it; %> import { message as Message } from '@c-x/ui' import type { AxiosInstance, AxiosRequestConfig, HeadersDefaults, ResponseType, AxiosResponse } from "axios"; import axios from "axios"; export type QueryParamsType = Record; export interface FullRequestParams extends Omit { /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; /** request path */ path: string; /** content type of request body */ type?: ContentType; /** query params */ query?: QueryParamsType; /** format of response (i.e. response.json() -> format: "json") */ format?: ResponseType; /** request body */ body?: unknown; } export type RequestParams = Omit; export interface ApiConfig extends Omit { securityWorker?: (securityData: SecurityDataType | null) => Promise | AxiosRequestConfig | void; secure?: boolean; format?: ResponseType; } export enum ContentType { Json = "application/json", FormData = "multipart/form-data", UrlEncoded = "application/x-www-form-urlencoded", Text = "text/plain", } const whitePathnameList = ['/user/login', '/login', '/auth', '/invite']; const whiteApiList = ['/api/v1/user/profile', '/api/v1/admin/profile']; const redirectToLogin = () => { const redirectAfterLogin = encodeURIComponent(location.href); const search = `redirect=${redirectAfterLogin}`; const pathname = location.pathname.startsWith('/user') ? '/login' : '/login/admin'; window.location.href = `${pathname}`; }; type ExtractDataProp = T extends { data?: infer U } ? U : never export class HttpClient { public instance: AxiosInstance; private securityData: SecurityDataType | null = null; private securityWorker?: ApiConfig["securityWorker"]; private secure?: boolean; private format?: ResponseType; constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig = {}) { this.instance = axios.create({ withCredentials: true, ...axiosConfig, baseURL: axiosConfig.baseURL || '' }) this.secure = secure; this.format = format; this.securityWorker = securityWorker; this.instance.interceptors.response.use( (resp) => { if (resp.data.code === 0) { return resp.data.data; } else { Message.error(resp.data.message) return Promise.reject(resp.data.message) } }, (err) => { if (err?.response?.status === 401) { if(whitePathnameList.find(item => location.pathname.startsWith(item))) { return Promise.reject('尚未登录'); } Message.error('尚未登录') redirectToLogin(); return Promise.reject('尚未登录'); } // 手动取消请求 if (err.code === 'ERR_CANCELED') { return } const msg = err?.response?.data?.message || err?.message Message.error(msg) return Promise.reject(msg) }, ) } public setSecurityData = (data: SecurityDataType | null) => { this.securityData = data } protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig { const method = params1.method || (params2 && params2.method) return { ...this.instance.defaults, ...params1, ...(params2 || {}), headers: { ...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) || {}), ...(params1.headers || {}), ...((params2 && params2.headers) || {}), }, }; } protected stringifyFormItem(formItem: unknown) { if (typeof formItem === "object" && formItem !== null) { return JSON.stringify(formItem); } else { return `${formItem}`; } } protected createFormData(input: Record): FormData { return Object.keys(input || {}).reduce((formData, key) => { const property = input[key]; const propertyContent: any[] = (property instanceof Array) ? property : [property] for (const formItem of propertyContent) { const isFileType = formItem instanceof Blob || formItem instanceof File; formData.append( key, isFileType ? formItem : this.stringifyFormItem(formItem) ); } return formData; }, new FormData()); } public request = async ({ secure, path, type, query, format, body, ...params <% if (config.unwrapResponseData) { %> }: FullRequestParams): Promise> => { <% } else { %> }: FullRequestParams): Promise> => { <% } %> const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {}; const requestParams = this.mergeRequestParams(params, secureParams); const responseFormat = (format || this.format) || undefined; if (type === ContentType.FormData && body && body !== null && typeof body === "object") { body = this.createFormData(body as Record); } if (type === ContentType.Text && body && body !== null && typeof body !== "string") { body = JSON.stringify(body); } return this.instance.request({ ...requestParams, headers: { ...(requestParams.headers || {}), ...(type && type !== ContentType.FormData ? { 'Content-Type': type } : {}), }, params: query, responseType: responseFormat, data: body, url: path, }) }; } export default new HttpClient({ format: 'json' }).request