Skip to content

Commit

Permalink
feat(projects): update @sa/axios
Browse files Browse the repository at this point in the history
  • Loading branch information
honghuangdc committed Jan 2, 2024
1 parent 7f049ba commit fd790fa
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 78 deletions.
3 changes: 1 addition & 2 deletions packages/axios/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"dependencies": {
"@sa/utils": "workspace:*",
"axios": "1.6.3",
"axios-retry": "^4.0.0",
"form-data": "^4.0.0"
"axios-retry": "^4.0.0"
}
}
27 changes: 16 additions & 11 deletions packages/axios/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ import axios from 'axios';
import type { CancelTokenSource, CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios';
import axiosRetry from 'axios-retry';
import { nanoid } from '@sa/utils';
import { createDefaultOptions, createRetryOptions } from './options';
import { getContentType, transformRequestData } from './shared';
import { createAxiosConfig, createDefaultOptions, createRetryOptions } from './options';
import { REQUEST_ID_KEY } from './constant';
import type { RequestInstance, RequestOption } from './type';

export function createRequest(axiosConfig?: CreateAxiosDefaults, options?: Partial<RequestOption>) {
const opts = createDefaultOptions(options);

const instance = axios.create(axiosConfig);
const axiosConf = createAxiosConfig(axiosConfig);
const instance = axios.create(axiosConf);

const cancelTokenSourceMap = new Map<string, CancelTokenSource>();

// config axios retry
const retryOptions = createRetryOptions(axiosConfig);
const retryOptions = createRetryOptions(axiosConf);
axiosRetry(instance, retryOptions);

instance.interceptors.request.use(conf => {
Expand All @@ -30,10 +30,6 @@ export function createRequest(axiosConfig?: CreateAxiosDefaults, options?: Parti
config.cancelToken = cancelTokenSource.token;
cancelTokenSourceMap.set(requestId, cancelTokenSource);

// transform data
const contentType = getContentType(config);
config.data = transformRequestData(config.data, contentType);

// handle config by hook
const handledConfig = opts.onRequest?.(config) || config;

Expand All @@ -42,11 +38,20 @@ export function createRequest(axiosConfig?: CreateAxiosDefaults, options?: Parti

instance.interceptors.response.use(
async response => {
console.log('response: ', response);
return response;
const backendSuccess = opts.onBackendSuccess(response);

if (backendSuccess) {
return Promise.resolve(response);
}

const fail = await opts.onBackendFail(response, instance);
if (fail) {
return fail;
}

return Promise.reject(response);
},
error => {
console.log('response error: ', error);
return Promise.reject(error);
}
);
Expand Down
17 changes: 17 additions & 0 deletions packages/axios/src/options.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { CreateAxiosDefaults } from 'axios';
import type { IAxiosRetryConfig } from 'axios-retry';
import { isHttpSuccess } from './shared';
import type { RequestOption } from './type';

export function createDefaultOptions(options?: Partial<RequestOption>) {
Expand All @@ -24,3 +25,19 @@ export function createRetryOptions(config?: Partial<CreateAxiosDefaults>) {

return retryConfig;
}

export function createAxiosConfig(config?: Partial<CreateAxiosDefaults>) {
const TEN_SECONDS = 10 * 1000;

const axiosConfig: CreateAxiosDefaults = {
timeout: TEN_SECONDS,
headers: {
'Content-Type': 'application/json'
},
validateStatus: isHttpSuccess
};

Object.assign(axiosConfig, config);

return axiosConfig;
}
65 changes: 20 additions & 45 deletions packages/axios/src/shared.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,28 @@
import FormData from 'form-data';
import type { AxiosHeaderValue, InternalAxiosRequestConfig } from 'axios';
import type { ContentType } from './type';
import type { AxiosHeaderValue, AxiosResponse, InternalAxiosRequestConfig } from 'axios';

export function transformRequestData(data: any, contentType: AxiosHeaderValue) {
if (typeof contentType !== 'string') return data;

const $contentType = contentType as ContentType;

// 1. "application/json": do not transform

// 2 "application/x-www-form-urlencoded": transform to query string
if ($contentType === 'application/x-www-form-urlencoded' && typeof data === 'object') {
const params = new URLSearchParams();
Object.keys(data).forEach(key => {
params.append(key, data[key]);
});

return params;
}

// 3. "multipart/form-data": transform to FormData
if ($contentType === 'multipart/form-data' && typeof data === 'object') {
const formData = new FormData();
const entries = Object.entries(data);

entries.forEach(([key, value]) => {
if (isFiles(value)) {
value.forEach(file => {
formData.append(key, file);
});
} else {
formData.append(key, value);
}
});
}
export function getContentType(config: InternalAxiosRequestConfig) {
const contentType: AxiosHeaderValue = config.headers?.['Content-Type'] || 'application/json';

return data;
return contentType;
}

function isFiles(data: File[] | unknown): data is File[] {
const isArray = Array.isArray(data);
const hasData = isArray && data.length > 0;
const isFile = hasData && Object.prototype.toString.call(data[0]) === '[object File]';

return isFile;
/**
* check if http status is success
*
* @param status
*/
export function isHttpSuccess(status: number) {
const isSuccessCode = status >= 200 && status < 300;
return isSuccessCode || status === 304;
}

export function getContentType(config: InternalAxiosRequestConfig) {
const contentType: AxiosHeaderValue = config.headers?.['Content-Type'] || 'application/json';
/**
* is response json
*
* @param response axios response
*/
export function isResponseJson(response: AxiosResponse) {
const { responseType } = response.config;

return contentType;
return responseType === 'json' || responseType === undefined;
}
3 changes: 0 additions & 3 deletions pnpm-lock.yaml

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

6 changes: 1 addition & 5 deletions src/service/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ export function fetchDebug() {

export function fetchDebugAxios() {
return axios<App.Service.Response<string>>('/debug-post', {
method: 'post',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: {
a: 1
}
method: 'post'
});
}
19 changes: 9 additions & 10 deletions src/service/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export const request = createRequest({
apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2'
},
onRequest(context) {
console.log('context: ', context);
const { headers } = context.options;

if (headers) {
Expand All @@ -23,16 +22,16 @@ export const request = createRequest({

Object.assign(headers, { Authorization });
}
},
onRequestError(context) {
console.error('onRequestError', context);
},
onResponse(context) {
console.log('onResponse', context);
},
onResponseError(context) {
console.log('onResponseError', context);
}
// onRequestError(context) {
// console.error('onRequestError', context);
// },
// onResponse(context) {
// console.log('onResponse', context);
// },
// onResponseError(context) {
// console.log('onResponseError', context);
// }
});

export const demoRequest = createRequest({ baseURL: isHttpProxy ? createProxyPattern('demo') : otherBaseURL.demo });
Expand Down
8 changes: 6 additions & 2 deletions src/views/home/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ async function start() {
}
async function startAxios() {
const data = await fetchDebugAxios();
console.log('data: ', data);
try {
const data = await fetchDebugAxios();
console.log('data: ', data);
} catch (error) {
console.log('error: ', error);
}
}
start();
Expand Down

0 comments on commit fd790fa

Please sign in to comment.