mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-29 22:56:41 +08:00
feat(packages): add @sa/alova
This commit is contained in:
parent
0ac95bdcf5
commit
494db95614
16
packages/alova/package.json
Normal file
16
packages/alova/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "@sa/alova",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"exports": {
|
||||||
|
".": "./src/index.ts"
|
||||||
|
},
|
||||||
|
"typesVersions": {
|
||||||
|
"*": {
|
||||||
|
"*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sa/utils": "workspace:*",
|
||||||
|
"alova": "^3.0.16"
|
||||||
|
}
|
||||||
|
}
|
5
packages/alova/src/constant.ts
Normal file
5
packages/alova/src/constant.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/** request id key */
|
||||||
|
export const REQUEST_ID_KEY = 'X-Request-Id';
|
||||||
|
|
||||||
|
/** the backend error code key */
|
||||||
|
export const BACKEND_ERROR_CODE = 'BACKEND_ERROR';
|
83
packages/alova/src/index.ts
Normal file
83
packages/alova/src/index.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { createAlova } from 'alova';
|
||||||
|
import VueHook from 'alova/vue';
|
||||||
|
import adapterFetch from 'alova/fetch';
|
||||||
|
import { nanoid } from '@sa/utils';
|
||||||
|
import { createServerTokenAuthentication } from 'alova/client';
|
||||||
|
import { BACKEND_ERROR_CODE, REQUEST_ID_KEY } from './constant';
|
||||||
|
import { isJSON } from './shared';
|
||||||
|
|
||||||
|
export interface CustomAlovaConfig {
|
||||||
|
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({
|
||||||
|
refreshTokenOnSuccess: {
|
||||||
|
isExpired: async response => {
|
||||||
|
const contentType = response.headers.get('Content-Type');
|
||||||
|
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 () => {
|
||||||
|
await options.refreshTokenHandler();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 附加token
|
||||||
|
assignToken: method => {
|
||||||
|
const token = localStorage.getItem('SOY_token');
|
||||||
|
method.config.headers.Authorization = token ? `Bearer ${JSON.parse(token)}` : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const instance = createAlova({
|
||||||
|
baseURL: customConfig.baseURL,
|
||||||
|
timeout: customConfig.timeout ?? 10 * 1000,
|
||||||
|
requestAdapter: adapterFetch(),
|
||||||
|
statesHook: VueHook,
|
||||||
|
beforeRequest: onAuthRequired(({ config }) => {
|
||||||
|
// 添加配置headers
|
||||||
|
config.headers = {
|
||||||
|
...config.headers,
|
||||||
|
...customConfig.headers
|
||||||
|
};
|
||||||
|
|
||||||
|
// set request id
|
||||||
|
const requestId = nanoid();
|
||||||
|
config.headers[REQUEST_ID_KEY] = requestId;
|
||||||
|
}),
|
||||||
|
responded: onResponseRefreshToken({
|
||||||
|
onSuccess: async resp => {
|
||||||
|
if (resp.ok || resp.status === 304) {
|
||||||
|
if (isJSON(resp.headers.get('Content-Type') ?? '')) {
|
||||||
|
const fail = await options.onBackendFail(resp);
|
||||||
|
if (fail) {
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
return await resp.json();
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
return Promise.reject(resp);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { BACKEND_ERROR_CODE, REQUEST_ID_KEY };
|
3
packages/alova/src/shared.ts
Normal file
3
packages/alova/src/shared.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function isJSON(contentType: string) {
|
||||||
|
return contentType.includes('application/json');
|
||||||
|
}
|
20
packages/alova/tsconfig.json
Normal file
20
packages/alova/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"jsx": "preserve",
|
||||||
|
"lib": ["DOM", "ESNext"],
|
||||||
|
"baseUrl": ".",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"types": ["node"],
|
||||||
|
"strict": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user