mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-29 22:56:41 +08:00
typo(packages): add types & update code
This commit is contained in:
parent
494db95614
commit
e7799d2db1
@ -1,24 +1,12 @@
|
|||||||
import { createAlova } from 'alova';
|
import { createAlova } from 'alova';
|
||||||
import VueHook from 'alova/vue';
|
import VueHook from 'alova/vue';
|
||||||
import adapterFetch from 'alova/fetch';
|
import adapterFetch from 'alova/fetch';
|
||||||
import { nanoid } from '@sa/utils';
|
|
||||||
import { createServerTokenAuthentication } from 'alova/client';
|
import { createServerTokenAuthentication } from 'alova/client';
|
||||||
import { BACKEND_ERROR_CODE, REQUEST_ID_KEY } from './constant';
|
import { BACKEND_ERROR_CODE, REQUEST_ID_KEY } from './constant';
|
||||||
import { isJSON } from './shared';
|
import { isJSON } from './shared';
|
||||||
|
import type { CustomAlovaConfig, RequestOptions } from './type';
|
||||||
|
|
||||||
export interface CustomAlovaConfig {
|
export const createAlovaRequest = (customConfig: CustomAlovaConfig<any>, options: RequestOptions<any>) => {
|
||||||
baseURL: string;
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
timeout?: number;
|
|
||||||
expiredTokenCodes: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RequestOptions {
|
|
||||||
refreshTokenHandler: () => Promise<boolean>;
|
|
||||||
onBackendFail: (response: Response) => Promise<Response | null>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createAlovaRequest = (customConfig: CustomAlovaConfig, options: RequestOptions) => {
|
|
||||||
const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication({
|
const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication({
|
||||||
refreshTokenOnSuccess: {
|
refreshTokenOnSuccess: {
|
||||||
isExpired: async response => {
|
isExpired: async response => {
|
||||||
@ -34,46 +22,60 @@ export const createAlovaRequest = (customConfig: CustomAlovaConfig, options: Req
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
handler: async () => {
|
handler: async () => {
|
||||||
await options.refreshTokenHandler();
|
if (options.refreshTokenHandler) {
|
||||||
|
await options.refreshTokenHandler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 附加token
|
refreshTokenOnError: {
|
||||||
assignToken: method => {
|
isExpired: async response => {
|
||||||
const token = localStorage.getItem('SOY_token');
|
const contentType = response.headers.get('Content-Type');
|
||||||
method.config.headers.Authorization = token ? `Bearer ${JSON.parse(token)}` : null;
|
if (isJSON(contentType ?? '')) {
|
||||||
|
const resp = response.clone();
|
||||||
|
const data = await resp.json();
|
||||||
|
const responseCode = String(data.code);
|
||||||
|
if (customConfig.expiredTokenCodes.includes(responseCode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
handler: async () => {
|
||||||
|
if (options.refreshTokenHandler) {
|
||||||
|
await options.refreshTokenHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const instance = createAlova({
|
const instance = createAlova({
|
||||||
baseURL: customConfig.baseURL,
|
...customConfig,
|
||||||
timeout: customConfig.timeout ?? 10 * 1000,
|
timeout: customConfig.timeout ?? 10 * 1000,
|
||||||
requestAdapter: adapterFetch(),
|
requestAdapter: customConfig.requestAdapter ?? adapterFetch(),
|
||||||
statesHook: VueHook,
|
statesHook: VueHook,
|
||||||
beforeRequest: onAuthRequired(({ config }) => {
|
beforeRequest: onAuthRequired(options.onRequest),
|
||||||
// 添加配置headers
|
|
||||||
config.headers = {
|
|
||||||
...config.headers,
|
|
||||||
...customConfig.headers
|
|
||||||
};
|
|
||||||
|
|
||||||
// set request id
|
|
||||||
const requestId = nanoid();
|
|
||||||
config.headers[REQUEST_ID_KEY] = requestId;
|
|
||||||
}),
|
|
||||||
responded: onResponseRefreshToken({
|
responded: onResponseRefreshToken({
|
||||||
onSuccess: async resp => {
|
onSuccess: async resp => {
|
||||||
|
// check if http status is success
|
||||||
if (resp.ok || resp.status === 304) {
|
if (resp.ok || resp.status === 304) {
|
||||||
if (isJSON(resp.headers.get('Content-Type') ?? '')) {
|
if (
|
||||||
|
!isJSON(resp.headers.get('Content-Type') ?? '') ||
|
||||||
|
(options.isBackendSuccess && (await options.isBackendSuccess(resp)))
|
||||||
|
) {
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
if (options.onBackendFail) {
|
||||||
const fail = await options.onBackendFail(resp);
|
const fail = await options.onBackendFail(resp);
|
||||||
if (fail) {
|
if (fail) {
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
return await resp.json();
|
|
||||||
}
|
}
|
||||||
return resp;
|
return options.transformBackendResponse ? await options.transformBackendResponse(resp) : resp;
|
||||||
}
|
}
|
||||||
return Promise.reject(resp);
|
throw new Error(resp.statusText);
|
||||||
}
|
},
|
||||||
|
onComplete: options.onComplete,
|
||||||
|
onError: options.onError
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -81,3 +83,4 @@ export const createAlovaRequest = (customConfig: CustomAlovaConfig, options: Req
|
|||||||
};
|
};
|
||||||
|
|
||||||
export { BACKEND_ERROR_CODE, REQUEST_ID_KEY };
|
export { BACKEND_ERROR_CODE, REQUEST_ID_KEY };
|
||||||
|
export type * from './type';
|
||||||
|
64
packages/alova/src/type.ts
Normal file
64
packages/alova/src/type.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import type {
|
||||||
|
AlovaGenerics,
|
||||||
|
AlovaOptions,
|
||||||
|
AlovaRequestAdapter,
|
||||||
|
Method,
|
||||||
|
ResponseCompleteHandler,
|
||||||
|
ResponseErrorHandler
|
||||||
|
} from 'alova';
|
||||||
|
|
||||||
|
export type CustomAlovaConfig<AG extends AlovaGenerics> = Omit<
|
||||||
|
AlovaOptions<AG>,
|
||||||
|
'statesHook' | 'beforeRequest' | 'responded' | 'requestAdapter'
|
||||||
|
> & {
|
||||||
|
/** expired token codes */
|
||||||
|
expiredTokenCodes: string[];
|
||||||
|
/** request adapter. all request of alova will be sent by it. */
|
||||||
|
requestAdapter?: AlovaRequestAdapter<AG['RequestConfig'], AG['Response'], AG['ResponseHeader']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface RequestOptions<AG extends AlovaGenerics> {
|
||||||
|
/**
|
||||||
|
* The hook before request
|
||||||
|
*
|
||||||
|
* For example: You can add header token in this hook
|
||||||
|
*
|
||||||
|
* @param method alova Method Instance
|
||||||
|
*/
|
||||||
|
onRequest?: (method: Method<AG>) => void | Promise<void>;
|
||||||
|
/**
|
||||||
|
* The hook to check backend response is success or not
|
||||||
|
*
|
||||||
|
* @param response Axios response
|
||||||
|
*/
|
||||||
|
isBackendSuccess?: (response: Response) => Promise<boolean>;
|
||||||
|
|
||||||
|
/** The hook to refresh token */
|
||||||
|
refreshTokenHandler?: () => Promise<void>;
|
||||||
|
/**
|
||||||
|
* The hook after backend request fail
|
||||||
|
*
|
||||||
|
* For example: You can handle the expired token in this hook
|
||||||
|
*
|
||||||
|
* @param response Axios response
|
||||||
|
* @param instance Axios instance
|
||||||
|
*/
|
||||||
|
onBackendFail?: (response: Response) => Promise<Response | null> | Promise<void>;
|
||||||
|
|
||||||
|
onComplete?: ResponseCompleteHandler<AG>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hook to handle error
|
||||||
|
*
|
||||||
|
* For example: You can show error message in this hook
|
||||||
|
*
|
||||||
|
* @param error
|
||||||
|
*/
|
||||||
|
onError?: ResponseErrorHandler<AG>;
|
||||||
|
/**
|
||||||
|
* transform backend response when the responseType is json
|
||||||
|
*
|
||||||
|
* @param response Axios response
|
||||||
|
*/
|
||||||
|
transformBackendResponse?: (response: AG['Response']) => any | Promise<any>;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user