feat: first commit
This commit is contained in:
137
src/http/index.ts
Normal file
137
src/http/index.ts
Normal file
@ -0,0 +1,137 @@
|
||||
import Taro, { UploadTask } from '@tarojs/taro';
|
||||
|
||||
import { HttpError } from '@/http/error';
|
||||
import { safeJsonParse } from '@/utils/common';
|
||||
|
||||
import { API, BASE_URL } from './api';
|
||||
import { HTTP_STATUS, RESPONSE_ERROR_CODE } from './constant';
|
||||
import interceptors from './interceptor';
|
||||
import { IRequestResponse } from './type';
|
||||
import { isTokenExpired, refreshToken } from './utils';
|
||||
|
||||
interface IRequestOption<T = BL.Anything> extends Taro.request.Option<T> {
|
||||
contentType?: 'application/json' | 'application/x-www-form-urlencoded';
|
||||
blRetryTime?: number;
|
||||
}
|
||||
|
||||
interface IUploadOption extends Taro.uploadFile.Option {
|
||||
blRetryTime?: number;
|
||||
onProgress?: UploadTask.OnProgressUpdateCallback;
|
||||
}
|
||||
|
||||
interceptors.forEach(interceptor => Taro.addInterceptor(interceptor));
|
||||
|
||||
class Http {
|
||||
private throwHttpError = (resp: Taro.request.SuccessCallbackResult<IRequestResponse>) => {
|
||||
const { statusCode, data } = resp;
|
||||
const errorCode = data?.code || 'null';
|
||||
const errorMsg = data?.msg || 'unknown';
|
||||
const traceId = data?.traceId;
|
||||
console.error(
|
||||
`http request fail, httpCode: ${statusCode}, errorCode: ${errorCode}, errorMsg: ${errorMsg}, traceId: ${traceId}`
|
||||
);
|
||||
throw new HttpError('request fail', errorCode, errorMsg, traceId);
|
||||
};
|
||||
|
||||
private isNeedLoginError = (
|
||||
options: { blRetryTime?: number },
|
||||
resp: Taro.request.SuccessCallbackResult<IRequestResponse>
|
||||
) => {
|
||||
if (options.blRetryTime && options.blRetryTime >= 3) {
|
||||
return false;
|
||||
}
|
||||
const { statusCode, data } = resp;
|
||||
return statusCode !== HTTP_STATUS.SUCCESS && data?.code === RESPONSE_ERROR_CODE.NEED_LOGIN;
|
||||
};
|
||||
|
||||
private uploadFile = (options: IUploadOption) => {
|
||||
const { onProgress, ...option } = options;
|
||||
let offProgressUpdate: (() => void) | null = null;
|
||||
return new Promise((resolve, reject) => {
|
||||
option.success = resolve;
|
||||
option.fail = reject;
|
||||
const task = Taro.uploadFile(option);
|
||||
onProgress && task.onProgressUpdate(onProgress);
|
||||
onProgress && (offProgressUpdate = () => task.offProgressUpdate(onProgress));
|
||||
})
|
||||
.then((resp: Taro.uploadFile.SuccessCallbackResult) => {
|
||||
if (resp.statusCode === 200) {
|
||||
return safeJsonParse(resp.data.replace(/\uFEFF/g, ''));
|
||||
} else if (this.isNeedLoginError(option, resp as Taro.request.SuccessCallbackResult)) {
|
||||
option.blRetryTime = (option.blRetryTime || 0) + 1;
|
||||
return refreshToken().then(() => this.uploadFile(option));
|
||||
} else {
|
||||
this.throwHttpError(resp as Taro.request.SuccessCallbackResult);
|
||||
}
|
||||
})
|
||||
.finally(() => offProgressUpdate?.());
|
||||
};
|
||||
|
||||
private request = (option: IRequestOption) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
option.success = resolve;
|
||||
option.fail = reject;
|
||||
Taro.request(option);
|
||||
}).then((resp: Taro.request.SuccessCallbackResult) => {
|
||||
if (resp.statusCode === HTTP_STATUS.SUCCESS) {
|
||||
return resp.data;
|
||||
} else if (this.isNeedLoginError(option, resp)) {
|
||||
option.blRetryTime = (option.blRetryTime || 0) + 1;
|
||||
return refreshToken().then(() => this.request(option));
|
||||
} else {
|
||||
this.throwHttpError(resp);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
private baseUpload = (params: IUploadOption) => {
|
||||
const { url, ...otherParams } = params;
|
||||
const option: IUploadOption = {
|
||||
// 默认超时时间三分钟
|
||||
timeout: 1000 * 60 * 3,
|
||||
...otherParams,
|
||||
blRetryTime: 0,
|
||||
url: url.startsWith('http') ? url : BASE_URL + url,
|
||||
header: { 'content-type': 'multipart/form-data' },
|
||||
};
|
||||
|
||||
return this.uploadFile(option);
|
||||
};
|
||||
|
||||
private baseRequest = (params: IRequestOption, method: Taro.request.Option['method'] = 'GET') => {
|
||||
const { url, data, ...otherParams } = params;
|
||||
const contentType = params.contentType || 'application/json';
|
||||
const option: IRequestOption = {
|
||||
...otherParams,
|
||||
blRetryTime: 0,
|
||||
url: BASE_URL + url,
|
||||
data,
|
||||
method: method,
|
||||
header: { 'content-type': contentType },
|
||||
};
|
||||
return this.request(option);
|
||||
};
|
||||
|
||||
async init() {
|
||||
if (isTokenExpired()) {
|
||||
await refreshToken();
|
||||
}
|
||||
}
|
||||
|
||||
get = <T = BL.Anything>(url: API, params?: Omit<IRequestOption<T>, 'url'>): Promise<T> => {
|
||||
const option = { url, ...params };
|
||||
return this.baseRequest(option);
|
||||
};
|
||||
|
||||
post = <T = BL.Anything>(url: API, params?: Omit<IRequestOption<T>, 'url'>): Promise<T> => {
|
||||
const option = { url, ...params };
|
||||
return this.baseRequest(option, 'POST');
|
||||
};
|
||||
|
||||
upload = <T = BL.Anything>(url: API | string, params?: Omit<IUploadOption, 'url'>): Promise<T> => {
|
||||
const option = { url, ...params } as IUploadOption;
|
||||
return this.baseUpload(option);
|
||||
};
|
||||
}
|
||||
|
||||
export default new Http();
|
||||
Reference in New Issue
Block a user