1. 新增网络相关错误的多语言翻译配置 2. 重写http请求层,添加自动重试机制与错误分类提示 3. 优化鸿蒙平台下的组件渲染兼容性与数据更新逻辑 4. 调整部分页面的模板结构与请求配置
274 lines
7.4 KiB
JavaScript
274 lines
7.4 KiB
JavaScript
import Config from './config.js'
|
|
import Util from './util.js'
|
|
import store from '@/store/index.js'
|
|
import Platform from './platform.js'
|
|
|
|
const { appType, appTypeName } = Platform.getPlatformInfo();
|
|
|
|
let _Lang = null;
|
|
function getLang() {
|
|
if (!_Lang) {
|
|
_Lang = require('./lang.js').default;
|
|
}
|
|
return _Lang;
|
|
}
|
|
|
|
const DEFAULT_TIMEOUT = 15000;
|
|
const DEFAULT_MAX_RETRIES = 2;
|
|
const RETRY_DELAY_BASE = 2000;
|
|
|
|
function _shouldRetry(errMsg) {
|
|
if (!errMsg) return false;
|
|
if (errMsg === 'request:fail url not in domain list') return false;
|
|
if (errMsg === 'request:fail abort') return false;
|
|
const retryableErrors = [
|
|
'request:fail timeout',
|
|
'request:fail connect',
|
|
'request:fail network'
|
|
];
|
|
return retryableErrors.some(err => errMsg.startsWith(err));
|
|
}
|
|
|
|
function _classifyError(errMsg, statusCode) {
|
|
if (!errMsg && !statusCode) return 'unknown';
|
|
if (errMsg === 'request:fail abort') return 'aborted';
|
|
if (errMsg && errMsg.indexOf('timeout') !== -1) return 'timeout';
|
|
if (errMsg && (errMsg.indexOf('connect') !== -1 || errMsg.indexOf('network') !== -1)) return 'networkError';
|
|
if (statusCode && statusCode >= 500) return 'serverError';
|
|
if (errMsg && errMsg.indexOf('url not in domain list') !== -1) return 'domainNotInList';
|
|
return 'unknown';
|
|
}
|
|
|
|
function _sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
function _makeRequest(url, method, data, header, dataType, responseType, timeout) {
|
|
return new Promise((resolve, reject) => {
|
|
uni.request({
|
|
url: url,
|
|
method: method,
|
|
data: data,
|
|
header: header,
|
|
dataType: dataType,
|
|
responseType: responseType,
|
|
timeout: timeout,
|
|
success: (res) => {
|
|
if (res.statusCode && [200, 500].indexOf(res.statusCode) == -1) {
|
|
reject({ errMsg: `request:fail statusCode=${res.statusCode}`, statusCode: res.statusCode });
|
|
return;
|
|
}
|
|
if (res.data.code == -3 && store.state.siteState > 0) {
|
|
store.commit('setSiteState', -3);
|
|
Util.redirectTo('/pages_tool/storeclose/storeclose', {}, 'reLaunch');
|
|
return;
|
|
}
|
|
if (res.data.refreshtoken) {
|
|
store.commit('setToken', res.data.refreshtoken);
|
|
}
|
|
if (res.data.code == -10009 || res.data.code == -10010) {
|
|
store.commit('setToken', '');
|
|
store.commit('setMemberInfo', '');
|
|
}
|
|
resolve(res.data);
|
|
},
|
|
fail: (res) => {
|
|
reject(res);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
async function _requestWithRetry(params, url, method, data, header, dataType, responseType) {
|
|
const timeout = params.timeout || DEFAULT_TIMEOUT;
|
|
const maxRetries = params.noRetry ? 0 : (params.maxRetries || DEFAULT_MAX_RETRIES);
|
|
let lastError = null;
|
|
let lastStatusCode = null;
|
|
|
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
try {
|
|
const result = await _makeRequest(url, method, data, header, dataType, responseType, timeout);
|
|
return result;
|
|
} catch (err) {
|
|
lastError = err;
|
|
lastStatusCode = err && err.statusCode;
|
|
if (attempt >= maxRetries || !_shouldRetry(err.errMsg)) {
|
|
break;
|
|
}
|
|
const delay = RETRY_DELAY_BASE * Math.pow(2, attempt);
|
|
await _sleep(delay);
|
|
}
|
|
}
|
|
|
|
if (params.silentError) {
|
|
throw lastError;
|
|
}
|
|
|
|
const errorType = _classifyError(lastError && lastError.errMsg, lastStatusCode);
|
|
const lang = getLang();
|
|
if (errorType === 'domainNotInList') {
|
|
uni.showToast({
|
|
title: lang.lang('http.domainNotInList', { url: Config.baseUrl }),
|
|
'icon': 'none',
|
|
duration: 10000
|
|
});
|
|
} else {
|
|
const i18nKey = 'http.' + errorType;
|
|
uni.showToast({
|
|
title: lang.lang(i18nKey),
|
|
'icon': 'none',
|
|
duration: 10000
|
|
});
|
|
}
|
|
throw lastError;
|
|
}
|
|
|
|
export default {
|
|
sendRequest(params) {
|
|
if (!Config.baseUrl) {
|
|
uni.showToast({
|
|
title: getLang().lang('http.baseUrlNotConfigured'),
|
|
'icon': 'none',
|
|
duration: 10000
|
|
});
|
|
return;
|
|
}
|
|
|
|
const _isRemoteOnly = getLang().isRemoteOnly && getLang().isRemoteOnly();
|
|
const _bootDone = getLang().isBootCompleted && getLang().isBootCompleted();
|
|
if (_isRemoteOnly && !_bootDone) {
|
|
let bootPromise = null;
|
|
try {
|
|
const app = getApp();
|
|
if (app && app.$langReady) bootPromise = app.$langReady;
|
|
} catch (e) {}
|
|
if (!bootPromise) bootPromise = getLang().boot();
|
|
|
|
if (params.async === false) {
|
|
return bootPromise.then(() => this._sendRequestNow(params));
|
|
} else {
|
|
bootPromise.then(() => this._sendRequestNow(params));
|
|
return;
|
|
}
|
|
}
|
|
|
|
return this._sendRequestNow(params);
|
|
},
|
|
|
|
_sendRequestNow(params) {
|
|
|
|
var method = params.data != undefined ? 'POST' : 'GET',
|
|
url = (Config.baseUrl + params.url).replace(/(?<!:)\/+/g, '/'),
|
|
data = {
|
|
app_type: appType,
|
|
app_type_name: appTypeName
|
|
};
|
|
|
|
data.token = store.state.token || '';
|
|
data.uniacid = uni.getStorageSync('uniacid') || Config.uniacid;
|
|
|
|
var default_store_info = store.state.defaultStoreInfo;
|
|
if (default_store_info) {
|
|
data.store_id = default_store_info.store_id;
|
|
}
|
|
|
|
var store_info = store.state.globalStoreInfo;
|
|
|
|
if (store_info) data.store_id = store_info.store_id;
|
|
|
|
if (params.data != undefined) Object.assign(data, params.data);
|
|
|
|
const header = params.header || {
|
|
'content-type': 'application/x-www-form-urlencoded;application/json'
|
|
};
|
|
const dataType = params.dataType || 'json';
|
|
const responseType = params.responseType || 'text';
|
|
|
|
if (params.async === false) {
|
|
return _requestWithRetry(params, url, method, data, header, dataType, responseType)
|
|
.then(res => {
|
|
typeof params.complete == 'function' && params.complete(res);
|
|
return res;
|
|
})
|
|
.catch(err => {
|
|
typeof params.complete == 'function' && params.complete();
|
|
throw err;
|
|
});
|
|
} else {
|
|
_requestWithRetry(params, url, method, data, header, dataType, responseType)
|
|
.then(res => {
|
|
typeof params.success == 'function' && params.success(res);
|
|
typeof params.complete == 'function' && params.complete(res);
|
|
})
|
|
.catch(err => {
|
|
typeof params.fail == 'function' && params.fail(err);
|
|
typeof params.complete == 'function' && params.complete();
|
|
});
|
|
}
|
|
},
|
|
uploadBase64(params) {
|
|
uni.request({
|
|
url: Config.baseUrl + '/api/upload/headimgBase64',
|
|
method: 'POST',
|
|
header: {
|
|
'content-type': 'application/x-www-form-urlencoded;application/json'
|
|
},
|
|
data: {
|
|
app_type: appType,
|
|
app_type_name: appTypeName,
|
|
images: params.base64
|
|
},
|
|
dataType: 'json',
|
|
responseType: 'text',
|
|
success: res => {
|
|
typeof params.success == 'function' && params.success(res.data);
|
|
},
|
|
fail: () => {
|
|
typeof params.fail == 'function' && params.fail(res);
|
|
}
|
|
});
|
|
},
|
|
pullImage(params) {
|
|
uni.request({
|
|
url: Config.baseUrl + '/api/upload/headimgPull',
|
|
method: 'POST',
|
|
header: {
|
|
'content-type': 'application/x-www-form-urlencoded;application/json'
|
|
},
|
|
data: {
|
|
app_type: appType,
|
|
app_type_name: appTypeName,
|
|
path: params.path
|
|
},
|
|
dataType: 'json',
|
|
responseType: 'text',
|
|
success: res => {
|
|
typeof params.success == 'function' && params.success(res.data);
|
|
},
|
|
fail: () => {
|
|
typeof params.fail == 'function' && params.fail(res);
|
|
}
|
|
});
|
|
},
|
|
upload(params) {
|
|
uni.uploadFile({
|
|
url: Config.baseUrl + params.url,
|
|
filePath: params.filePath,
|
|
name: params.name || 'file',
|
|
fileType: params.fileType || 'image',
|
|
formData: {
|
|
app_type: appType,
|
|
app_type_name: appTypeName,
|
|
},
|
|
header: {
|
|
'content-type': 'application/x-www-form-urlencoded;application/json'
|
|
},
|
|
success: (res) => {
|
|
typeof params.success == 'function' && params.success(JSON.parse(res.data));
|
|
},
|
|
fail: (res) => {
|
|
typeof params.fail == 'function' && params.fail(res);
|
|
}
|
|
});
|
|
}
|
|
} |