|
@@ -0,0 +1,247 @@
|
|
|
|
|
+import ApiCofig from "@/common/config/ApiCofig";
|
|
|
|
|
+import AppCofig, { isDev } from "@/common/config/AppCofig";
|
|
|
|
|
+import { useAuthStore } from "@/stores/auth";
|
|
|
|
|
+import { RequestCoreInstance, RequestApiError, StringUtils, appendGetUrlParams, appendPostParams, RequestResponse, RequestOptions, type RequestApiInfoStruct, RequestApiResult, type RequestApiErrorType, defaultResponseDataGetErrorInfo, defaultResponseDataHandlerCatch, WebFetchImplementer, RequestApiConfig } from "@imengyu/imengyu-utils";
|
|
|
|
|
+import type { DataModel, KeyValue, NewDataModel } from "@imengyu/js-request-transform";
|
|
|
|
|
+import { Modal } from "ant-design-vue";
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 说明:业务相关的请求模块
|
|
|
|
|
+ * * 请求数据处理函数。
|
|
|
|
|
+ * * 自定义请求模块。
|
|
|
|
|
+ * * 自定义错误报告处理函数。
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+function matchNotReportMessage(code: number, str: string) {
|
|
|
|
|
+ if (ApiCofig.notReportErrorCode.includes(code))
|
|
|
|
|
+ return true;
|
|
|
|
|
+ for (let i = 0; i < ApiCofig.notReportMessages.length; i++) {
|
|
|
|
|
+ if (ApiCofig.notReportMessages[i]?.test(str))
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+//错误报告处理
|
|
|
|
|
+export function reportError<T extends DataModel>(instance: RequestCoreInstance<T>, response: RequestApiError | Error) {
|
|
|
|
|
+ if (isDev) {
|
|
|
|
|
+ //开发模式下直接弹窗显示
|
|
|
|
|
+ if (response instanceof RequestApiError) {
|
|
|
|
|
+ console.error({
|
|
|
|
|
+ message: `请求错误 ${response.apiName} : ${response.errorMessage}`,
|
|
|
|
|
+ detail: response.toString() +
|
|
|
|
|
+ '\r\n请求接口:' + response.apiName +
|
|
|
|
|
+ '\r\n请求地址:' + response.apiUrl +
|
|
|
|
|
+ '\r\n请求参数:' + JSON.stringify(response.apiRawReq) +
|
|
|
|
|
+ '\r\n返回参数:' + JSON.stringify(response.rawData) +
|
|
|
|
|
+ '\r\n状态码:' + response.code +
|
|
|
|
|
+ '\r\n信息:' + response.errorCodeMessage,
|
|
|
|
|
+ type: 'error',
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.error({
|
|
|
|
|
+ message: '错误报告 代码错误',
|
|
|
|
|
+ detail: response?.stack || ('' + response),
|
|
|
|
|
+ type: 'error',
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ let errMsg = '';
|
|
|
|
|
+ if (response instanceof RequestApiError)
|
|
|
|
|
+ errMsg = response.errorMessage + '。';
|
|
|
|
|
+
|
|
|
|
|
+ errMsg += '服务出现了异常,请稍后重试或联系客服。';
|
|
|
|
|
+ errMsg += '版本:' + AppCofig.version;
|
|
|
|
|
+
|
|
|
|
|
+ Modal.error({
|
|
|
|
|
+ title: '抱歉',
|
|
|
|
|
+ content: errMsg,
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export class BaseAppServerRequestModule<T extends DataModel> extends RequestCoreInstance<T> {
|
|
|
|
|
+ constructor(baseUrl: string) {
|
|
|
|
|
+ super(WebFetchImplementer);
|
|
|
|
|
+ this.config.baseUrl = baseUrl;
|
|
|
|
|
+ this.config.errCodes = [];
|
|
|
|
|
+ //请求拦截器
|
|
|
|
|
+ this.config.requestInterceptor = (url, req) => {
|
|
|
|
|
+ //获取store中的token,追加到头;
|
|
|
|
|
+ const autoStore = useAuthStore();
|
|
|
|
|
+ if (StringUtils.isNullOrEmpty((req.headers as KeyValue).token as string)) {
|
|
|
|
|
+ if (!StringUtils.isNullOrEmpty(autoStore.token)) {
|
|
|
|
|
+ req.headers['token'] = autoStore.token;
|
|
|
|
|
+ req.headers['__token__'] = autoStore.token;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (req.method == 'GET') {
|
|
|
|
|
+ //追加GET参数
|
|
|
|
|
+ url = appendGetUrlParams(url, 'main_body_id', ApiCofig.mainBodyId);
|
|
|
|
|
+ //url = appendGetUrlParams(url, 'platform', ApiCofig.platformId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (!(req.data instanceof FormData)) {
|
|
|
|
|
+ req.data = appendPostParams(req.data,'main_body_id', ApiCofig.mainBodyId);
|
|
|
|
|
+ //req.data = appendPostParams(req.data,'platform', ApiCofig.platformId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ req.data.append('main_body_id', ApiCofig.mainBodyId.toString());
|
|
|
|
|
+ //req.data = appendPostParams(req.data,'platform', ApiCofig.platformId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return { newUrl: url, newReq: req };
|
|
|
|
|
+ };
|
|
|
|
|
+ //响应数据处理函数
|
|
|
|
|
+ this.config.responseDataHandler = async function responseDataHandler<T extends DataModel>(response: RequestResponse, req: RequestOptions, resultModelClass: NewDataModel | undefined, instance: RequestCoreInstance<T>, apiInfo: RequestApiInfoStruct): Promise<RequestApiResult<T>> {
|
|
|
|
|
+ const method = req.method || 'GET';
|
|
|
|
|
+ try {
|
|
|
|
|
+ const json = await response.json();
|
|
|
|
|
+ if (response.ok) {
|
|
|
|
|
+ if (!json) {
|
|
|
|
|
+ throw new RequestApiError(
|
|
|
|
|
+ 'businessError',
|
|
|
|
|
+ '后端未返回数据',
|
|
|
|
|
+ '',
|
|
|
|
|
+ response.status,
|
|
|
|
|
+ null,
|
|
|
|
|
+ null,
|
|
|
|
|
+ response.headers,
|
|
|
|
|
+ apiInfo
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //code == 0 错误
|
|
|
|
|
+ if (json.code === 0) {
|
|
|
|
|
+ throw createError(json);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //处理后端的数据
|
|
|
|
|
+ let message = '未知错误';
|
|
|
|
|
+ let data = {} as any;
|
|
|
|
|
+
|
|
|
|
|
+ //后端返回格式不统一,所以在这里处理格式
|
|
|
|
|
+ if (typeof json.data === 'object') {
|
|
|
|
|
+ data = json.data;
|
|
|
|
|
+ message = json.data?.msg || response.statusText;
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ //否则返回上层对象
|
|
|
|
|
+ data = json;
|
|
|
|
|
+ message = json.msg || response.statusText;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return new RequestApiResult(
|
|
|
|
|
+ resultModelClass ?? instance.config.modelClassCreator,
|
|
|
|
|
+ json?.code || response.status,
|
|
|
|
|
+ message,
|
|
|
|
|
+ data,
|
|
|
|
|
+ json,
|
|
|
|
|
+ response.headers,
|
|
|
|
|
+ apiInfo
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ throw createError(json);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function createError(json: any): RequestApiError {
|
|
|
|
|
+ let errType : RequestApiErrorType = 'unknow';
|
|
|
|
|
+ let errString = '';
|
|
|
|
|
+ let errCodeStr = '';
|
|
|
|
|
+
|
|
|
|
|
+ if (typeof json.message === 'string')
|
|
|
|
|
+ errString = json.message;
|
|
|
|
|
+ if (typeof json.msg === 'string')
|
|
|
|
|
+ errString += json.msg;
|
|
|
|
|
+
|
|
|
|
|
+ if (StringUtils.isStringAllEnglish(errString))
|
|
|
|
|
+ errString = '服务器返回:' + errString;
|
|
|
|
|
+
|
|
|
|
|
+ //错误处理
|
|
|
|
|
+ if (errString) {
|
|
|
|
|
+ //如果后端有返回错误信息,则收集错误信息并返回
|
|
|
|
|
+ errType = 'businessError';
|
|
|
|
|
+ if (typeof json.data === 'object' && json.data?.errmsg) {
|
|
|
|
|
+ errString += '\n' + json.data.errmsg;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (typeof json.errors === 'object') {
|
|
|
|
|
+ for (const key in json.errors) {
|
|
|
|
|
+ if (Object.prototype.hasOwnProperty.call(json.errors, key)) {
|
|
|
|
|
+ errString += '\n' + json.errors[key];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const res = defaultResponseDataGetErrorInfo(response, json);
|
|
|
|
|
+ errType = res.errType;
|
|
|
|
|
+ errString = res.errString;
|
|
|
|
|
+ errCodeStr = res.errCodeStr;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const res = new RequestApiError(
|
|
|
|
|
+ errType,
|
|
|
|
|
+ errString,
|
|
|
|
|
+ errCodeStr,
|
|
|
|
|
+ response.status,
|
|
|
|
|
+ null,
|
|
|
|
|
+ null,
|
|
|
|
|
+ response.headers,
|
|
|
|
|
+ apiInfo
|
|
|
|
|
+ );
|
|
|
|
|
+ console.log(res);
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ if (err instanceof RequestApiError) {
|
|
|
|
|
+ throw err;
|
|
|
|
|
+ }
|
|
|
|
|
+ //错误统一处理
|
|
|
|
|
+ return new Promise<RequestApiResult<T>>((resolve, reject) => {
|
|
|
|
|
+ defaultResponseDataHandlerCatch(method, req, response, null, err as any, apiInfo, response.url, reject, instance);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }; /**
|
|
|
|
|
+ * 此函数用于请求失败时,如何处理错误信息
|
|
|
|
|
+ *
|
|
|
|
|
+ * NOTE: 这里配置Api请求时要如何处理错误
|
|
|
|
|
+ * @param err 错误信息实例
|
|
|
|
|
+ * @param response 返回数据
|
|
|
|
|
+ * @returns 返回一个 Promise,可以定义最终调用该接口的代码会接收到什么样的错误对象。
|
|
|
|
|
+ */
|
|
|
|
|
+ this.config.responseErrorHandler = (err, instance, apiInfo) => {
|
|
|
|
|
+ function createErr(errorType: RequestApiErrorType, message: string) {
|
|
|
|
|
+ return new RequestApiError(errorType, message, undefined, undefined, undefined, err, undefined, apiInfo);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (err instanceof Error) {
|
|
|
|
|
+ if (err.message == 'Network Error')
|
|
|
|
|
+ return createErr('networkError', '请求失败,请检查您的网络连接?');
|
|
|
|
|
+ if (err.message.includes('Timeout')
|
|
|
|
|
+ || err.message.includes('timeout')
|
|
|
|
|
+ || err.message.includes('singal'))
|
|
|
|
|
+ return createErr('networkError', '请求超时');
|
|
|
|
|
+ if (err.message.includes('cancelled')
|
|
|
|
|
+ || err.message.includes('aborted'))
|
|
|
|
|
+ return createErr('networkError', '请求已取消');
|
|
|
|
|
+ if (err.message.includes('AbortError'))
|
|
|
|
|
+ return createErr('networkError', '请求失败,请检查您的网络连接?');
|
|
|
|
|
+ return createErr('scriptError', err.message);
|
|
|
|
|
+ } else if (err instanceof RequestApiError) {
|
|
|
|
|
+ return err;
|
|
|
|
|
+ }
|
|
|
|
|
+ return createErr('unknow', '请求失败,未知错误:' + err);
|
|
|
|
|
+ };
|
|
|
|
|
+ //错误报告处理
|
|
|
|
|
+ this.config.responseErrorReportInterceptor = (instance, response) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ (response.errorType !== 'businessError' && response.errorType !== 'networkError') ||
|
|
|
|
|
+ matchNotReportMessage(response.code, response.errorMessage) === true
|
|
|
|
|
+ );
|
|
|
|
|
+ };
|
|
|
|
|
+ //错误报告处理函数
|
|
|
|
|
+ this.config.reportError = reportError;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+RequestApiConfig.setConfig({
|
|
|
|
|
+ ...RequestApiConfig.getConfig(),
|
|
|
|
|
+ EnableApiDataLog: false,
|
|
|
|
|
+ EnableApiRequestLog: import.meta.env.DEV,
|
|
|
|
|
+})
|