Skip to content

Commit

Permalink
feat: axios全局开启适配器
Browse files Browse the repository at this point in the history
BREAKING CHANGE: 缓存默认关闭
  • Loading branch information
geekact committed Jul 21, 2024
1 parent 95e29be commit 42a6eb8
Show file tree
Hide file tree
Showing 26 changed files with 358 additions and 274 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
]
},
"dependencies": {
"axios": "~1.1.3",
"axios": "^1.7.2",
"clone": "^2.1.2"
},
"devDependencies": {
Expand Down
24 changes: 12 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 23 additions & 27 deletions src/enhancer.ts → src/enhance.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import {
default as axios,
default as originAxios,
AxiosInstance,
AxiosRequestConfig,
CreateAxiosDefaults,
getAdapter,
} from 'axios';
import { CacheSlot, CacheOptions, CacheFormatConfig } from './slots/CacheSlot';
import { preventTransform, TransformResponseHandler } from './libs/preventTransform';
import { overrideRequest, FocaAxiosPromise } from './libs/overrideRequest';
import { RetryOptions, RetrySlot } from './slots/RetrySlot';
import { ThrottleSlot, ThrottleOptions } from './slots/ThrottleSlot';
import { RequestSlot } from './slots/RequestSlot';
import { CacheSlot, CacheOptions, CacheFormatConfig } from './slots/cache-slot';
import { preventTransform, TransformResponseHandler } from './libs/prevent-transform';
import { overrideRequest, FocaAxiosPromise } from './libs/override-request';
import { RetryOptions, RetrySlot } from './slots/retry-slot';
import { ThrottleSlot, ThrottleOptions } from './slots/throttle-slot';
import { RequestSlot } from './slots/request-slot';

declare module 'axios' {
export interface CreateAxiosDefaults {
enhance?(instance: AxiosInstance): AxiosInstance | void;
}

export interface AxiosRequestConfig<D = any> {
/**
* 相同请求共享。
Expand Down Expand Up @@ -90,31 +86,26 @@ declare module 'axios' {
}
}

const originalCreate = axios.create;
// @ts-ignore
axios.create = (config: CreateAxiosDefaults = {}): Enhancer => {
const instance = originalCreate(config);
return config.enhance
? config.enhance(instance) || instance
: enhance(instance, config);
};

/**
* axios增强适配器,使用`axios.create()`创建的实例无需手动执行该函数
* axios增强适配器
*/
export const enhance = (
instance: AxiosInstance,
export const enhance = <T extends AxiosInstance>(
instance: T,
options: CreateAxiosDefaults = {},
): AxiosInstance => {
): T => {
overrideRequest(instance);

const cache = new CacheSlot(options.cache);
const throttle = new ThrottleSlot(options.throttle);
const request = new RequestSlot(instance.defaults.adapter!, options.getHttpStatus);
const request = new RequestSlot(
getAdapter(instance.defaults.adapter!),
options.getHttpStatus,
);
const retry = new RetrySlot(options.retry);
const validateRetry = retry.validate.bind(retry);

instance.defaults.adapter = function focaAdapter(config: AxiosRequestConfig) {
instance.defaults.adapter = function focaAdapter(config) {
console.log('=-----====adapter');
const transformHandler: TransformResponseHandler = [];
const promise = Promise.resolve().then(() => {
return cache.hit(config, () => {
Expand All @@ -130,3 +121,8 @@ export const enhance = (

return instance;
};

export const axios = enhance(originAxios, originAxios.defaults);

const defaultCreate = axios.create;
axios.create = (config) => enhance(defaultCreate(config));
11 changes: 2 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
export * from './enhancer';
export * from './slots/CacheSlot';
export * from './slots/ThrottleSlot';
export * from './slots/RetrySlot';
export * from './libs/overrideRequest';
export * from './libs/preventTransform';
export * from './libs/mergeSlotOptions';
export * from './libs/cloneResponse';
export * from './enhance';
export * from 'axios';
export { default as axios } from 'axios';
export { axios as default } from './enhance';
7 changes: 5 additions & 2 deletions src/libs/cloneResponse.ts → src/libs/clone-response.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import clone from 'clone';
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import type { InternalAxiosRequestConfig, AxiosResponse } from 'axios';

/**
* request作为XMLHttpRequest被clone时会出错
* @see XMLHttpRequest
*/
export const cloneResponse = (response: AxiosResponse, config: AxiosRequestConfig) => {
export const cloneResponse = (
response: AxiosResponse,
config: InternalAxiosRequestConfig,
) => {
const next = Object.assign({}, response);

next.data = clone(next.data, false);
Expand Down
5 changes: 0 additions & 5 deletions src/libs/isForceEnable.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/libs/merge-slot-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
interface BaseConfig {
enable?: boolean;
}

export const mergeSlotOptions = <T extends BaseConfig>(
globalOptions?: boolean | T,
localOptions?: boolean | T,
): T => {
const globalOpts: BaseConfig | undefined =
typeof globalOptions === 'undefined'
? {}
: typeof globalOptions === 'boolean'
? { enable: globalOptions }
: { enable: true, ...globalOptions };
const localOpts: BaseConfig | undefined =
typeof localOptions === 'undefined'
? {}
: typeof localOptions === 'boolean'
? { enable: localOptions }
: { enable: true, ...localOptions };

return Object.assign({ enable: true }, globalOpts, localOpts) as T;
};
25 changes: 0 additions & 25 deletions src/libs/mergeSlotOptions.ts

This file was deleted.

41 changes: 41 additions & 0 deletions src/libs/override-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Axios, AxiosRequestConfig, type AxiosInstance, type AxiosResponse } from 'axios';

export interface FocaAxiosPromise<T = any, D = any> extends Promise<T> {
/**
* 返回axios原始的response格式
* @see AxiosResponse
*/
toRaw: () => Promise<AxiosResponse<T, D>>;
}

export const overrideRequest = (instance: AxiosInstance) => {
// 真实的上下文 context = new Axios(),但是未暴露出来,导致 instance.request 与 context.request 不是同一个。
Object.keys(Axios.prototype).forEach((key) => {
// @ts-expect-error
if (typeof Axios.prototype[key] === 'function') {
Object.defineProperty(instance, key, {
get() {
// @ts-expect-error
return Axios.prototype[key].bind(instance);
},
enumerable: true,
});
}
});

instance.request = function overrideRequest(config?: AxiosRequestConfig<any>) {
let shouldUnwrap: boolean = true;
const promise = Axios.prototype.request
.call(instance, config || {})
.then((response) => {
return shouldUnwrap ? (response as AxiosResponse).data : response;
}) as FocaAxiosPromise;

promise.toRaw = function toRawResponse() {
shouldUnwrap = false;
return promise;
};

return promise;
};
};
34 changes: 0 additions & 34 deletions src/libs/overrideRequest.ts

This file was deleted.

File renamed without changes.
27 changes: 14 additions & 13 deletions src/slots/CacheSlot.ts → src/slots/cache-slot.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import type { AxiosRequestConfig, AxiosResponse, Method } from 'axios';
import type {
AxiosRequestConfig,
AxiosResponse,
InternalAxiosRequestConfig,
Method,
} from 'axios';
import clone from 'clone';
import { cloneResponse } from '../libs/cloneResponse';
import { mergeSlotOptions } from '../libs/mergeSlotOptions';
import { isForceEnable } from '../libs/isForceEnable';
import { cloneResponse } from '../libs/clone-response';
import { mergeSlotOptions } from '../libs/merge-slot-options';

export interface CacheOptions {
/**
* 是否允许使用缓存。默认:`true`
* 是否允许使用缓存。默认:`false`
*/
enable?: boolean;
/**
Expand All @@ -26,7 +30,7 @@ export interface CacheOptions {
*/
format?(formatConfig: CacheFormatConfig): object | string;
/**
* 对于过滤后初步允许缓存的请求,执行该方法再次确认。
* 允许使用缓存的请求,执行该方法再次确认。
*/
validate?(config: AxiosRequestConfig): boolean;
}
Expand All @@ -51,20 +55,17 @@ export class CacheSlot {

protected cacheMap: CacheMap = {};

constructor(protected readonly options?: boolean | CacheOptions) {}
constructor(protected readonly options: boolean | CacheOptions = false) {}

hit(
config: AxiosRequestConfig,
newCache: (config: AxiosRequestConfig) => Promise<AxiosResponse>,
config: InternalAxiosRequestConfig,
newCache: (config: InternalAxiosRequestConfig) => Promise<AxiosResponse>,
): Promise<AxiosResponse> {
const options = mergeSlotOptions(this.options, config.cache);
const { allowedMethods = CacheSlot.defaultAllowedMethods, validate } = options;
const enable =
options.enable !== false &&
(isForceEnable(config.cache) ||
allowedMethods.includes(
config.method!.toLowerCase() as `${Lowercase<Method>}`,
)) &&
allowedMethods.includes(config.method!.toLowerCase() as `${Lowercase<Method>}`) &&
(!validate || validate(config));

if (!enable) {
Expand Down
Loading

0 comments on commit 42a6eb8

Please sign in to comment.