204 lines
6.8 KiB
JavaScript
204 lines
6.8 KiB
JavaScript
/**
|
||
* 网络请求工具类
|
||
* 封装统一的网络请求方法
|
||
*/
|
||
|
||
import EnvConfig from '@/common/env.js';
|
||
import md5 from 'js-md5';
|
||
import { getLocalStorage, setLocalStorage } from './cacheService';
|
||
import qs from 'qs';
|
||
class request {
|
||
/**
|
||
* 生成唯一的nonce值
|
||
* @returns {String} nonce值
|
||
*/
|
||
static generateNonce() {
|
||
return md5(Date.now() + Math.random().toString(36).substring(2, 15));
|
||
}
|
||
|
||
/**
|
||
* 创建签名
|
||
* @param {Object} data 请求数据
|
||
* @param {String} host 主机名
|
||
* @returns {Object} 带签名的数据和参数字符串
|
||
* @private
|
||
*/
|
||
static _createSignature(data, host) {
|
||
// 添加时间戳
|
||
data.timestamp = Math.floor(Date.now() / 1000);
|
||
// 添加nonce随机字符串
|
||
data.nonce = request.generateNonce();
|
||
|
||
// 按照键名对参数进行排序
|
||
const sortedParams = {};
|
||
Object.keys(data).sort().forEach(key => {
|
||
sortedParams[key] = data[key];
|
||
});
|
||
|
||
// 组合参数为字符串
|
||
let signStr = '';
|
||
for (const key in sortedParams) {
|
||
if (typeof sortedParams[key] === 'object') {
|
||
signStr += key + '=' + JSON.stringify(sortedParams[key]) + '&';
|
||
} else {
|
||
signStr += key + '=' + sortedParams[key] + '&';
|
||
}
|
||
}
|
||
|
||
// 获取时间戳,组合为密钥
|
||
const timestamp = data.timestamp;
|
||
const appSecret = host + timestamp;
|
||
|
||
// 添加密钥并去除最后的&
|
||
signStr = signStr.substring(0, signStr.length - 1) + appSecret;
|
||
|
||
// 使用MD5生成签名
|
||
const sign = md5(signStr);
|
||
data.sign = sign;
|
||
|
||
return { data, signStr };
|
||
}
|
||
|
||
/**
|
||
* 构建请求URL
|
||
* @param {String} url 请求路径
|
||
* @returns {Object} 包含请求URL和主机名的对象
|
||
* @private
|
||
*/
|
||
static _buildRequestUrl(url) {
|
||
let requestUrl = '';
|
||
|
||
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||
// 如果是完整的URL,直接使用
|
||
requestUrl = url;
|
||
} else {
|
||
// 否则拼接基础URL和相对路径
|
||
// 确保基础URL以/结尾,而请求路径不以/开头
|
||
const apiBaseUrl = EnvConfig.apiBaseUrl;
|
||
const baseUrlWithSlash = apiBaseUrl.endsWith('/') ? apiBaseUrl : apiBaseUrl + '/';
|
||
let routeMap = url;
|
||
const path = routeMap.startsWith('/') ? routeMap.substring(1) : routeMap;
|
||
requestUrl = baseUrlWithSlash + path;
|
||
}
|
||
|
||
// 使用正则表达式从URL中提取主机名
|
||
const hostRegex = /^(?:https?:\/\/)?([^\/]+)/i;
|
||
const matches = requestUrl.match(hostRegex);
|
||
const host = matches && matches[1] ? matches[1] : 'localhost';
|
||
|
||
return { requestUrl, host };
|
||
}
|
||
|
||
/**
|
||
* 发送请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} fromData 请求数据
|
||
* @param {String} method 请求方式
|
||
* @param {Boolean} showLoading 是否显示加载提示
|
||
* @returns {Promise} 返回请求Promise
|
||
*/
|
||
static request(url, fromData = {}, method = 'POST', showLoading = false) {
|
||
return new Promise((resolve, reject) => {
|
||
// 使用传入的method而不是重新声明
|
||
const requestMethod = method.toUpperCase();
|
||
const token = uni.getStorageSync('token');
|
||
let data = { ...fromData }; // 创建数据的深拷贝,避免修改原数据
|
||
|
||
// 构建请求URL和提取主机名
|
||
const { requestUrl, host } = request._buildRequestUrl(url);
|
||
|
||
// 显示加载提示
|
||
if (showLoading) {
|
||
uni.showLoading({
|
||
title: '正在加载中...',
|
||
mask: true
|
||
});
|
||
}
|
||
|
||
// 创建签名并准备请求数据和头信息
|
||
const { data: signedData } = request._createSignature(data, host);
|
||
data = signedData;
|
||
// 根据请求方法设置不同的headers
|
||
const header = {
|
||
Authorization: 'Bearer ' + token,
|
||
'content-type': 'application/json'
|
||
};
|
||
|
||
const startDate = Date.now();
|
||
|
||
// 发起网络请求
|
||
uni.request({
|
||
url: requestUrl,
|
||
method: requestMethod,
|
||
header: header,
|
||
data: data,
|
||
timeout: 30000, // 设置30秒超时
|
||
success: res => {
|
||
const endDate = Date.now();
|
||
console.log(requestUrl, "请求消耗时间", endDate - startDate);
|
||
resolve(res.data);
|
||
},
|
||
fail: e => {
|
||
console.error('网络请求失败:', e);
|
||
uni.showToast({
|
||
title: e.errMsg || '发送请求失败,请稍后再试!',
|
||
icon: 'none'
|
||
});
|
||
reject(e);
|
||
},
|
||
complete: () => {
|
||
if (showLoading) {
|
||
uni.hideLoading();
|
||
}
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 发送GET请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} data 请求参数
|
||
* @param {Boolean} showLoading 是否显示加载提示
|
||
* @returns {Promise} 返回请求Promise
|
||
*/
|
||
static get(url, data = {}, showLoading = false) {
|
||
return request.request(url, data, 'GET', showLoading);
|
||
}
|
||
|
||
/**
|
||
* 发送POST请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} data 请求参数
|
||
* @param {Boolean} showLoading 是否显示加载提示
|
||
* @returns {Promise} 返回请求Promise
|
||
*/
|
||
static post(url, data = {}, showLoading = false) {
|
||
return request.request(url, data, 'POST', showLoading);
|
||
}
|
||
|
||
/**
|
||
* 发送get请求,如果缓存存在,则返回缓存数据,否则发送请求,并缓存数据
|
||
* @param {String} url 请求地址
|
||
* @param {Object} data 请求参数
|
||
* @param {Number} time 缓存时间,秒
|
||
* @param {Boolean} showLoading 是否显示加载提示
|
||
* @returns {Promise} 返回请求Promise
|
||
*/
|
||
static async getOrCache(url, data = {}, time = 300, showLoading = false) {
|
||
const cacheKey = 'cache_' + url + '_' + qs.stringify(data);
|
||
// console.log('getOrCache', cacheKey, '查询缓存');
|
||
const cacheData = getLocalStorage(cacheKey);
|
||
if (cacheData) {
|
||
console.log('getOrCache', cacheKey, '缓存命中');
|
||
return cacheData;
|
||
}
|
||
|
||
const res = await request.request(url, data, 'GET', showLoading);
|
||
setLocalStorage(cacheKey, res, time);
|
||
return res;
|
||
}
|
||
|
||
}
|
||
|
||
export default request;
|