mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 16:46:19 +08:00
refactor(project): re-adjust the overall folder
This commit is contained in:
7
packages/effects/request/build.config.ts
Normal file
7
packages/effects/request/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
49
packages/effects/request/package.json
Normal file
49
packages/effects/request/package.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@vben/request",
|
||||
"version": "5.0.0",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "packages/effects/request"
|
||||
},
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"#build": "pnpm unbuild"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"sideEffects": [
|
||||
"**/*.css"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"development": "./src/index.ts",
|
||||
"#default": "./dist/index.mjs",
|
||||
"default": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@vben/locales": "workspace:*",
|
||||
"@vben/utils": "workspace:*",
|
||||
"axios": "^1.7.2",
|
||||
"vue-request": "^2.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios-mock-adapter": "^1.22.0"
|
||||
}
|
||||
}
|
3
packages/effects/request/src/index.ts
Normal file
3
packages/effects/request/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './request-client';
|
||||
export * from './use-request';
|
||||
export * from 'axios';
|
2
packages/effects/request/src/request-client/index.ts
Normal file
2
packages/effects/request/src/request-client/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './request-client';
|
||||
export type * from './types';
|
@@ -0,0 +1,84 @@
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { FileDownloader } from './downloader';
|
||||
|
||||
describe('fileDownloader', () => {
|
||||
let fileDownloader: FileDownloader;
|
||||
const mockAxiosInstance = {
|
||||
get: vi.fn(),
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
fileDownloader = new FileDownloader(mockAxiosInstance);
|
||||
});
|
||||
|
||||
it('should create an instance of FileDownloader', () => {
|
||||
expect(fileDownloader).toBeInstanceOf(FileDownloader);
|
||||
});
|
||||
|
||||
it('should download a file and return a Blob', async () => {
|
||||
const url = 'https://example.com/file';
|
||||
const mockBlob = new Blob(['file content'], { type: 'text/plain' });
|
||||
const mockResponse: Blob = mockBlob;
|
||||
|
||||
mockAxiosInstance.get.mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await fileDownloader.download(url);
|
||||
|
||||
expect(result).toBeInstanceOf(Blob);
|
||||
expect(result).toEqual(mockBlob);
|
||||
expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
});
|
||||
|
||||
it('should merge provided config with default config', async () => {
|
||||
const url = 'https://example.com/file';
|
||||
const mockBlob = new Blob(['file content'], { type: 'text/plain' });
|
||||
const mockResponse: Blob = mockBlob;
|
||||
|
||||
mockAxiosInstance.get.mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const customConfig: AxiosRequestConfig = {
|
||||
headers: { 'Custom-Header': 'value' },
|
||||
};
|
||||
|
||||
const result = await fileDownloader.download(url, customConfig);
|
||||
expect(result).toBeInstanceOf(Blob);
|
||||
expect(result).toEqual(mockBlob);
|
||||
expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {
|
||||
...customConfig,
|
||||
responseType: 'blob',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
const url = 'https://example.com/file';
|
||||
mockAxiosInstance.get.mockRejectedValueOnce(new Error('Network Error'));
|
||||
await expect(fileDownloader.download(url)).rejects.toThrow('Network Error');
|
||||
});
|
||||
|
||||
it('should handle empty URL gracefully', async () => {
|
||||
const url = '';
|
||||
mockAxiosInstance.get.mockRejectedValueOnce(
|
||||
new Error('Request failed with status code 404'),
|
||||
);
|
||||
|
||||
await expect(fileDownloader.download(url)).rejects.toThrow(
|
||||
'Request failed with status code 404',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle null URL gracefully', async () => {
|
||||
const url = null as unknown as string;
|
||||
mockAxiosInstance.get.mockRejectedValueOnce(
|
||||
new Error('Request failed with status code 404'),
|
||||
);
|
||||
|
||||
await expect(fileDownloader.download(url)).rejects.toThrow(
|
||||
'Request failed with status code 404',
|
||||
);
|
||||
});
|
||||
});
|
@@ -0,0 +1,30 @@
|
||||
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
|
||||
import type { RequestClient } from '../request-client';
|
||||
|
||||
class FileDownloader {
|
||||
private client: RequestClient;
|
||||
|
||||
constructor(client: RequestClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async download(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<Blob>> {
|
||||
const finalConfig: AxiosRequestConfig = {
|
||||
...config,
|
||||
responseType: 'blob',
|
||||
};
|
||||
|
||||
const response = await this.client.get<AxiosResponse<Blob>>(
|
||||
url,
|
||||
finalConfig,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
export { FileDownloader };
|
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
AxiosInstance,
|
||||
AxiosResponse,
|
||||
type InternalAxiosRequestConfig,
|
||||
} from 'axios';
|
||||
|
||||
const errorHandler = (res: Error) => Promise.reject(res);
|
||||
|
||||
class InterceptorManager {
|
||||
private axiosInstance: AxiosInstance;
|
||||
|
||||
constructor(instance: AxiosInstance) {
|
||||
this.axiosInstance = instance;
|
||||
}
|
||||
|
||||
addRequestInterceptor(
|
||||
fulfilled: (
|
||||
config: InternalAxiosRequestConfig,
|
||||
) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
|
||||
rejected?: (error: any) => any,
|
||||
) {
|
||||
this.axiosInstance.interceptors.request.use(
|
||||
fulfilled,
|
||||
rejected || errorHandler,
|
||||
);
|
||||
}
|
||||
|
||||
addResponseInterceptor<T = any>(
|
||||
fulfilled: (
|
||||
response: AxiosResponse<T>,
|
||||
) => AxiosResponse | Promise<AxiosResponse>,
|
||||
rejected?: (error: any) => any,
|
||||
) {
|
||||
this.axiosInstance.interceptors.response.use(
|
||||
fulfilled,
|
||||
rejected || errorHandler,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { InterceptorManager };
|
@@ -0,0 +1,118 @@
|
||||
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { FileUploader } from './uploader';
|
||||
|
||||
describe('fileUploader', () => {
|
||||
let fileUploader: FileUploader;
|
||||
// Mock the AxiosInstance
|
||||
const mockAxiosInstance = {
|
||||
post: vi.fn(),
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
fileUploader = new FileUploader(mockAxiosInstance);
|
||||
});
|
||||
|
||||
it('should create an instance of FileUploader', () => {
|
||||
expect(fileUploader).toBeInstanceOf(FileUploader);
|
||||
});
|
||||
|
||||
it('should upload a file and return the response', async () => {
|
||||
const url = 'https://example.com/upload';
|
||||
const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
|
||||
const mockResponse: AxiosResponse = {
|
||||
config: {} as any,
|
||||
data: { success: true },
|
||||
headers: {},
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
};
|
||||
|
||||
(
|
||||
mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
|
||||
).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await fileUploader.upload(url, file);
|
||||
expect(result).toEqual(mockResponse);
|
||||
expect(mockAxiosInstance.post).toHaveBeenCalledWith(
|
||||
url,
|
||||
expect.any(FormData),
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should merge provided config with default config', async () => {
|
||||
const url = 'https://example.com/upload';
|
||||
const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
|
||||
const mockResponse: AxiosResponse = {
|
||||
config: {} as any,
|
||||
data: { success: true },
|
||||
headers: {},
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
};
|
||||
|
||||
(
|
||||
mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
|
||||
).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const customConfig: AxiosRequestConfig = {
|
||||
headers: { 'Custom-Header': 'value' },
|
||||
};
|
||||
|
||||
const result = await fileUploader.upload(url, file, customConfig);
|
||||
expect(result).toEqual(mockResponse);
|
||||
expect(mockAxiosInstance.post).toHaveBeenCalledWith(
|
||||
url,
|
||||
expect.any(FormData),
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
'Custom-Header': 'value',
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
const url = 'https://example.com/upload';
|
||||
const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
|
||||
(
|
||||
mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
|
||||
).mockRejectedValueOnce(new Error('Network Error'));
|
||||
|
||||
await expect(fileUploader.upload(url, file)).rejects.toThrow(
|
||||
'Network Error',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle empty URL gracefully', async () => {
|
||||
const url = '';
|
||||
const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
|
||||
(
|
||||
mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
|
||||
).mockRejectedValueOnce(new Error('Request failed with status code 404'));
|
||||
|
||||
await expect(fileUploader.upload(url, file)).rejects.toThrow(
|
||||
'Request failed with status code 404',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle null URL gracefully', async () => {
|
||||
const url = null as unknown as string;
|
||||
const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
|
||||
(
|
||||
mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
|
||||
).mockRejectedValueOnce(new Error('Request failed with status code 404'));
|
||||
|
||||
await expect(fileUploader.upload(url, file)).rejects.toThrow(
|
||||
'Request failed with status code 404',
|
||||
);
|
||||
});
|
||||
});
|
@@ -0,0 +1,32 @@
|
||||
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
|
||||
import type { RequestClient } from '../request-client';
|
||||
|
||||
class FileUploader {
|
||||
private client: RequestClient;
|
||||
|
||||
constructor(client: RequestClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async upload(
|
||||
url: string,
|
||||
file: Blob | File,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const finalConfig: AxiosRequestConfig = {
|
||||
...config,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
...config?.headers,
|
||||
},
|
||||
};
|
||||
|
||||
return this.client.post(url, formData, finalConfig);
|
||||
}
|
||||
}
|
||||
|
||||
export { FileUploader };
|
@@ -0,0 +1,97 @@
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { RequestClient } from './request-client';
|
||||
|
||||
describe('requestClient', () => {
|
||||
let mock: MockAdapter;
|
||||
let requestClient: RequestClient;
|
||||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
requestClient = new RequestClient();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.reset();
|
||||
});
|
||||
|
||||
it('should successfully make a GET request', async () => {
|
||||
mock.onGet('test/url').reply(200, { data: 'response' });
|
||||
|
||||
const response = await requestClient.get('test/url');
|
||||
|
||||
expect(response.data).toEqual({ data: 'response' });
|
||||
});
|
||||
|
||||
it('should successfully make a POST request', async () => {
|
||||
const postData = { key: 'value' };
|
||||
const mockData = { data: 'response' };
|
||||
mock.onPost('/test/post', postData).reply(200, mockData);
|
||||
const response = await requestClient.post('/test/post', postData);
|
||||
expect(response.data).toEqual(mockData);
|
||||
});
|
||||
|
||||
it('should successfully make a PUT request', async () => {
|
||||
const putData = { key: 'updatedValue' };
|
||||
const mockData = { data: 'updated response' };
|
||||
mock.onPut('/test/put', putData).reply(200, mockData);
|
||||
const response = await requestClient.put('/test/put', putData);
|
||||
expect(response.data).toEqual(mockData);
|
||||
});
|
||||
|
||||
it('should successfully make a DELETE request', async () => {
|
||||
const mockData = { data: 'delete response' };
|
||||
mock.onDelete('/test/delete').reply(200, mockData);
|
||||
const response = await requestClient.delete('/test/delete');
|
||||
expect(response.data).toEqual(mockData);
|
||||
});
|
||||
|
||||
it('should handle network errors', async () => {
|
||||
mock.onGet('/test/error').networkError();
|
||||
try {
|
||||
await requestClient.get('/test/error');
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
expect(error.isAxiosError).toBe(true);
|
||||
expect(error.message).toBe('Network Error');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle timeout', async () => {
|
||||
mock.onGet('/test/timeout').timeout();
|
||||
try {
|
||||
await requestClient.get('/test/timeout');
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
expect(error.isAxiosError).toBe(true);
|
||||
expect(error.code).toBe('ECONNABORTED');
|
||||
}
|
||||
});
|
||||
|
||||
it('should successfully upload a file', async () => {
|
||||
const fileData = new Blob(['file contents'], { type: 'text/plain' });
|
||||
|
||||
mock.onPost('/test/upload').reply((config) => {
|
||||
return config.data instanceof FormData && config.data.has('file')
|
||||
? [200, { data: 'file uploaded' }]
|
||||
: [400, { error: 'Bad Request' }];
|
||||
});
|
||||
|
||||
const response = await requestClient.upload('/test/upload', fileData);
|
||||
expect(response.data).toEqual({ data: 'file uploaded' });
|
||||
});
|
||||
|
||||
it('should successfully download a file as a blob', async () => {
|
||||
const mockFileContent = new Blob(['mock file content'], {
|
||||
type: 'text/plain',
|
||||
});
|
||||
|
||||
mock.onGet('/test/download').reply(200, mockFileContent);
|
||||
|
||||
const res = await requestClient.download('/test/download');
|
||||
|
||||
expect(res.data).toBeInstanceOf(Blob);
|
||||
});
|
||||
});
|
238
packages/effects/request/src/request-client/request-client.ts
Normal file
238
packages/effects/request/src/request-client/request-client.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import type {
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
CreateAxiosDefaults,
|
||||
InternalAxiosRequestConfig,
|
||||
} from 'axios';
|
||||
|
||||
import type {
|
||||
MakeAuthorizationFn,
|
||||
MakeErrorMessageFn,
|
||||
RequestClientOptions,
|
||||
} from './types';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
import { merge } from '@vben/utils';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
import { FileDownloader } from './modules/downloader';
|
||||
import { InterceptorManager } from './modules/interceptor';
|
||||
import { FileUploader } from './modules/uploader';
|
||||
|
||||
class RequestClient {
|
||||
private instance: AxiosInstance;
|
||||
private makeAuthorization: MakeAuthorizationFn | undefined;
|
||||
private makeErrorMessage: MakeErrorMessageFn | undefined;
|
||||
|
||||
public addRequestInterceptor: InterceptorManager['addRequestInterceptor'];
|
||||
public addResponseInterceptor: InterceptorManager['addResponseInterceptor'];
|
||||
public download: FileDownloader['download'];
|
||||
public upload: FileUploader['upload'];
|
||||
|
||||
/**
|
||||
* 构造函数,用于创建Axios实例
|
||||
* @param options - Axios请求配置,可选
|
||||
*/
|
||||
constructor(options: RequestClientOptions = {}) {
|
||||
this.bindMethods();
|
||||
// 合并默认配置和传入的配置
|
||||
const defaultConfig: CreateAxiosDefaults = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
},
|
||||
// 默认超时时间
|
||||
timeout: 10_000,
|
||||
};
|
||||
const { makeAuthorization, makeErrorMessage, ...axiosConfig } = options;
|
||||
const requestConfig = merge(axiosConfig, defaultConfig);
|
||||
|
||||
this.instance = axios.create(requestConfig);
|
||||
this.makeAuthorization = makeAuthorization;
|
||||
this.makeErrorMessage = makeErrorMessage;
|
||||
|
||||
// 实例化拦截器管理器
|
||||
const interceptorManager = new InterceptorManager(this.instance);
|
||||
this.addRequestInterceptor =
|
||||
interceptorManager.addRequestInterceptor.bind(interceptorManager);
|
||||
this.addResponseInterceptor =
|
||||
interceptorManager.addResponseInterceptor.bind(interceptorManager);
|
||||
|
||||
// 实例化文件上传器
|
||||
const fileUploader = new FileUploader(this);
|
||||
this.upload = fileUploader.upload.bind(fileUploader);
|
||||
// 实例化文件下载器
|
||||
const fileDownloader = new FileDownloader(this);
|
||||
this.download = fileDownloader.download.bind(fileDownloader);
|
||||
|
||||
// 设置默认的拦截器
|
||||
this.setupInterceptors();
|
||||
}
|
||||
|
||||
private bindMethods() {
|
||||
const propertyNames = Object.getOwnPropertyNames(
|
||||
Object.getPrototypeOf(this),
|
||||
);
|
||||
propertyNames.forEach((propertyName) => {
|
||||
const propertyValue = (this as any)[propertyName];
|
||||
if (
|
||||
typeof propertyValue === 'function' &&
|
||||
propertyName !== 'constructor'
|
||||
) {
|
||||
(this as any)[propertyName] = propertyValue.bind(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private setupAuthorizationInterceptor() {
|
||||
this.addRequestInterceptor(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
const authorization = this.makeAuthorization?.(config);
|
||||
if (authorization) {
|
||||
const { token } = authorization.tokenHandler?.() ?? {};
|
||||
config.headers[authorization.key || 'Authorization'] = token;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error: any) => Promise.reject(error),
|
||||
);
|
||||
}
|
||||
|
||||
private setupDefaultResponseInterceptor() {
|
||||
this.addResponseInterceptor(
|
||||
(response: AxiosResponse) => {
|
||||
return response;
|
||||
},
|
||||
(error: any) => {
|
||||
if (axios.isCancel(error)) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
const err: string = error?.toString?.() ?? '';
|
||||
let errMsg = '';
|
||||
if (err?.includes('Network Error')) {
|
||||
errMsg = $t('fallback.http.networkError');
|
||||
} else if (error?.message?.includes?.('timeout')) {
|
||||
errMsg = $t('fallback.http.requestTimeout');
|
||||
}
|
||||
if (errMsg) {
|
||||
this.makeErrorMessage?.(errMsg);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
let errorMessage = error?.response?.data?.error?.message ?? '';
|
||||
const status = error?.response?.status;
|
||||
|
||||
switch (status) {
|
||||
case 400: {
|
||||
errorMessage = $t('fallback.http.badRequest');
|
||||
break;
|
||||
}
|
||||
|
||||
case 401: {
|
||||
errorMessage = $t('fallback.http.unauthorized');
|
||||
this.makeAuthorization?.().unAuthorizedHandler?.();
|
||||
break;
|
||||
}
|
||||
case 403: {
|
||||
errorMessage = $t('fallback.http.forbidden');
|
||||
break;
|
||||
}
|
||||
// 404请求不存在
|
||||
case 404: {
|
||||
errorMessage = $t('fallback.http.notFound');
|
||||
break;
|
||||
}
|
||||
case 408: {
|
||||
errorMessage = $t('fallback.http.requestTimeout');
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
errorMessage = $t('fallback.http.internalServerError');
|
||||
}
|
||||
}
|
||||
|
||||
this.makeErrorMessage?.(errorMessage);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private setupInterceptors() {
|
||||
// 默认拦截器
|
||||
this.setupAuthorizationInterceptor();
|
||||
this.setupDefaultResponseInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE请求方法
|
||||
* @param {string} url - 请求的URL
|
||||
* @param {AxiosRequestConfig} config - 请求配置(可选)
|
||||
* @returns 返回Promise
|
||||
*/
|
||||
public delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.request<T>(url, { ...config, method: 'DELETE' });
|
||||
}
|
||||
|
||||
/**
|
||||
* GET请求方法
|
||||
* @param {string} url - 请求URL
|
||||
* @param {AxiosRequestConfig} config - 请求配置,可选
|
||||
* @returns {Promise<AxiosResponse<T>>} 返回Axios响应Promise
|
||||
*/
|
||||
public get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.request<T>(url, { ...config, method: 'GET' });
|
||||
}
|
||||
|
||||
/**
|
||||
* POST请求方法
|
||||
* @param {string} url - 请求URL
|
||||
* @param {any} data - 请求体数据
|
||||
* @param {AxiosRequestConfig} config - 请求配置,可选
|
||||
* @returns {Promise<AxiosResponse<T>>} 返回Axios响应Promise
|
||||
*/
|
||||
public post<T = any>(
|
||||
url: string,
|
||||
data?: any,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<T> {
|
||||
return this.request<T>(url, { ...config, data, method: 'POST' });
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT请求方法
|
||||
* @param {string} url - 请求的URL
|
||||
* @param {any} data - 请求体数据
|
||||
* @param {AxiosRequestConfig} config - 请求配置(可选)
|
||||
* @returns 返回Promise
|
||||
*/
|
||||
public put<T = any>(
|
||||
url: string,
|
||||
data?: any,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<T> {
|
||||
return this.request<T>(url, { ...config, data, method: 'PUT' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的请求方法
|
||||
* @param {string} url - 请求的URL
|
||||
* @param {AxiosRequestConfig} config - 请求配置对象
|
||||
* @returns {Promise<AxiosResponse<T>>} 返回Axios响应Promise
|
||||
*/
|
||||
public async request<T>(url: string, config: AxiosRequestConfig): Promise<T> {
|
||||
try {
|
||||
const response: AxiosResponse<T> = await this.instance({
|
||||
url,
|
||||
...config,
|
||||
});
|
||||
return response as T;
|
||||
} catch (error: any) {
|
||||
throw error.response ? error.response.data : error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { RequestClient };
|
48
packages/effects/request/src/request-client/types.ts
Normal file
48
packages/effects/request/src/request-client/types.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios';
|
||||
|
||||
type RequestContentType =
|
||||
| 'application/json;charset=utf-8'
|
||||
| 'application/octet-stream;charset=utf-8'
|
||||
| 'application/x-www-form-urlencoded;charset=utf-8'
|
||||
| 'multipart/form-data;charset=utf-8';
|
||||
|
||||
interface MakeAuthorization {
|
||||
key?: string;
|
||||
tokenHandler: () => { refreshToken: string; token: string } | null;
|
||||
unAuthorizedHandler?: () => Promise<void>;
|
||||
}
|
||||
|
||||
type MakeAuthorizationFn = (
|
||||
config?: InternalAxiosRequestConfig,
|
||||
) => MakeAuthorization;
|
||||
|
||||
type MakeErrorMessageFn = (message: string) => void;
|
||||
|
||||
interface RequestClientOptions extends CreateAxiosDefaults {
|
||||
/**
|
||||
* 用于生成Authorization
|
||||
*/
|
||||
makeAuthorization?: MakeAuthorizationFn;
|
||||
/**
|
||||
* 用于生成错误消息
|
||||
*/
|
||||
makeErrorMessage?: MakeErrorMessageFn;
|
||||
}
|
||||
|
||||
interface HttpResponse<T = any> {
|
||||
/**
|
||||
* 0 表示成功 其他表示失败
|
||||
* 0 means success, others means fail
|
||||
*/
|
||||
code: number;
|
||||
data: T;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
HttpResponse,
|
||||
MakeAuthorizationFn,
|
||||
MakeErrorMessageFn,
|
||||
RequestClientOptions,
|
||||
RequestContentType,
|
||||
};
|
11
packages/effects/request/src/use-request.ts
Normal file
11
packages/effects/request/src/use-request.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// import { setGlobalOptions, } from 'vue-request';
|
||||
|
||||
// setGlobalOptions({
|
||||
// manual: true,
|
||||
// // ...
|
||||
// });
|
||||
|
||||
/**
|
||||
* @see https://www.attojs.com/guide/documentation/globalOptions.html
|
||||
*/
|
||||
export * from 'vue-request';
|
6
packages/effects/request/tsconfig.json
Normal file
6
packages/effects/request/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/web.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Reference in New Issue
Block a user