|
| 1 | +import { defineService, META_SERVICE } from '@opentiny/tiny-engine-meta-register' |
| 2 | +import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse, type CreateAxiosDefaults } from 'axios' |
| 3 | + |
| 4 | +// 请求拦截器 fulfilled 函数类型 |
| 5 | +type RequestInterceptorFulfilled = (config: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig> |
| 6 | + |
| 7 | +// 响应拦截器 fulfilled 函数类型 |
| 8 | +type ResponseInterceptorFulfilled<T = unknown> = ( |
| 9 | + response: AxiosResponse<T> |
| 10 | +) => AxiosResponse<T> | Promise<AxiosResponse<T>> |
| 11 | + |
| 12 | +// 拦截器 rejected 函数类型 |
| 13 | +type InterceptorRejected = (error: unknown) => unknown |
| 14 | + |
| 15 | +// 请求拦截器函数类型(单个 fulfilled 函数 或 [fulfilled, rejected] 元组) |
| 16 | +type RequestInterceptorFunction = RequestInterceptorFulfilled | [RequestInterceptorFulfilled, InterceptorRejected?] |
| 17 | + |
| 18 | +// 响应拦截器函数类型(单个 fulfilled 函数 或 [fulfilled, rejected] 元组) |
| 19 | +type ResponseInterceptorFunction<T = unknown> = |
| 20 | + | ResponseInterceptorFulfilled<T> |
| 21 | + | [ResponseInterceptorFulfilled<T>, InterceptorRejected?] |
| 22 | + |
| 23 | +// 请求拦截器配置类型(支持单个函数、数组、嵌套数组) |
| 24 | +type RequestInterceptorConfig = RequestInterceptorFunction | (RequestInterceptorFunction | undefined)[] |
| 25 | + |
| 26 | +// 响应拦截器配置类型(支持单个函数、数组、嵌套数组) |
| 27 | +type ResponseInterceptorConfig = ResponseInterceptorFunction | (ResponseInterceptorFunction | undefined)[] |
| 28 | + |
| 29 | +// 通用拦截器类型(用于内部处理) |
| 30 | +type InterceptorFunction = RequestInterceptorFunction | ResponseInterceptorFunction |
| 31 | +type InterceptorConfig = RequestInterceptorConfig | ResponseInterceptorConfig |
| 32 | + |
| 33 | +// 拦截器配置接口 |
| 34 | +interface InterceptorsConfig { |
| 35 | + request?: RequestInterceptorConfig |
| 36 | + response?: ResponseInterceptorConfig |
| 37 | +} |
| 38 | + |
| 39 | +// HTTP 服务选项接口 |
| 40 | +interface HttpServiceOptions { |
| 41 | + axiosConfig?: CreateAxiosDefaults |
| 42 | + interceptors?: InterceptorsConfig |
| 43 | +} |
| 44 | + |
| 45 | +let http: AxiosInstance | null = null |
| 46 | + |
| 47 | +// 通用拦截器 fulfilled 函数类型 |
| 48 | +type InterceptorFulfilled = RequestInterceptorFulfilled | ResponseInterceptorFulfilled |
| 49 | + |
| 50 | +// 通用拦截器处理器类型(内部使用) |
| 51 | +type InterceptorHandler = { |
| 52 | + use: (onFulfilled?: (value: any) => any, onRejected?: (error: unknown) => unknown) => number |
| 53 | +} |
| 54 | + |
| 55 | +/** |
| 56 | + * 注册单个拦截器 |
| 57 | + */ |
| 58 | +const registerInterceptor = (handler: InterceptorHandler, interceptor: InterceptorFunction): void => { |
| 59 | + if (typeof interceptor === 'function') { |
| 60 | + handler.use(interceptor) |
| 61 | + } else if (Array.isArray(interceptor)) { |
| 62 | + handler.use(interceptor[0], interceptor[1]) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +/** |
| 67 | + * 注册拦截器配置(支持单个函数、元组、或数组) |
| 68 | + */ |
| 69 | +const registerInterceptors = (handler: InterceptorHandler, config?: InterceptorConfig): void => { |
| 70 | + if (!config) return |
| 71 | + |
| 72 | + // 单个函数 |
| 73 | + if (typeof config === 'function') { |
| 74 | + handler.use(config) |
| 75 | + return |
| 76 | + } |
| 77 | + |
| 78 | + // 数组情况:判断是元组还是拦截器数组 |
| 79 | + if (Array.isArray(config)) { |
| 80 | + const isTuple = config.length <= 2 && typeof config[0] === 'function' && typeof config[1] !== 'object' |
| 81 | + |
| 82 | + if (isTuple) { |
| 83 | + // [fulfilled, rejected?] 元组 |
| 84 | + handler.use(config[0] as InterceptorFulfilled, config[1] as InterceptorRejected | undefined) |
| 85 | + } else { |
| 86 | + // 拦截器数组 |
| 87 | + config.forEach((item) => item && registerInterceptor(handler, item as InterceptorFunction)) |
| 88 | + } |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | +export default defineService({ |
| 93 | + id: META_SERVICE.Http, |
| 94 | + type: 'MetaService', |
| 95 | + initialState: {}, |
| 96 | + options: { |
| 97 | + axiosConfig: { |
| 98 | + // axios 配置 |
| 99 | + baseURL: '', |
| 100 | + withCredentials: false, // 跨域请求时是否需要使用凭证 |
| 101 | + headers: {} // 请求头 |
| 102 | + }, |
| 103 | + interceptors: { |
| 104 | + // 拦截器 |
| 105 | + request: [], // 支持配置多个请求拦截器,先注册后执行 |
| 106 | + response: [] // 支持配置多个响应拦截器,先注册先执行 |
| 107 | + } |
| 108 | + } as HttpServiceOptions, |
| 109 | + init: ({ options = {} }: { options?: HttpServiceOptions }) => { |
| 110 | + const { axiosConfig = {}, interceptors = {} } = options |
| 111 | + const { request, response } = interceptors |
| 112 | + |
| 113 | + http = axios.create(axiosConfig) |
| 114 | + registerInterceptors(http.interceptors.request, request) |
| 115 | + registerInterceptors(http.interceptors.response, response) |
| 116 | + }, |
| 117 | + apis: () => ({ |
| 118 | + /** 获取 axios 实例 */ |
| 119 | + getHttp: (): AxiosInstance | null => http, |
| 120 | + |
| 121 | + /** GET 请求 */ |
| 122 | + get: <T = unknown, R = AxiosResponse<T>, D = unknown>( |
| 123 | + url: string, |
| 124 | + config?: AxiosRequestConfig<D> |
| 125 | + ): Promise<R> | undefined => http?.get<T, R, D>(url, config), |
| 126 | + |
| 127 | + /** POST 请求 */ |
| 128 | + post: <T = unknown, R = AxiosResponse<T>, D = unknown>( |
| 129 | + url: string, |
| 130 | + data?: D, |
| 131 | + config?: AxiosRequestConfig<D> |
| 132 | + ): Promise<R> | undefined => http?.post<T, R, D>(url, data, config), |
| 133 | + |
| 134 | + /** 通用请求方法 */ |
| 135 | + request: <T = unknown, R = AxiosResponse<T>, D = unknown>(config: AxiosRequestConfig<D>): Promise<R> | undefined => |
| 136 | + http?.request<T, R, D>(config), |
| 137 | + |
| 138 | + /** PUT 请求 */ |
| 139 | + put: <T = unknown, R = AxiosResponse<T>, D = unknown>( |
| 140 | + url: string, |
| 141 | + data?: D, |
| 142 | + config?: AxiosRequestConfig<D> |
| 143 | + ): Promise<R> | undefined => http?.put<T, R, D>(url, data, config), |
| 144 | + |
| 145 | + /** DELETE 请求 */ |
| 146 | + delete: <T = unknown, R = AxiosResponse<T>, D = unknown>( |
| 147 | + url: string, |
| 148 | + config?: AxiosRequestConfig<D> |
| 149 | + ): Promise<R> | undefined => http?.delete<T, R, D>(url, config), |
| 150 | + |
| 151 | + /** 流式请求 */ |
| 152 | + stream: <T = unknown>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> | undefined => { |
| 153 | + const streamConfig: AxiosRequestConfig = { |
| 154 | + responseType: 'stream', |
| 155 | + ...config |
| 156 | + } |
| 157 | + return http?.request<T>(streamConfig) |
| 158 | + } |
| 159 | + }) |
| 160 | +}) |
0 commit comments