Files
boluo-app-main/src/http/index.ts
2025-06-05 22:47:41 +08:00

138 lines
4.7 KiB
TypeScript

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 /*'user-Id': '588002047871053824' */ },
};
return this.request(option);
};
async init(inviteCode?: string) {
if (isTokenExpired()) {
await refreshToken(inviteCode);
}
}
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();