240 lines
7.1 KiB
JavaScript
240 lines
7.1 KiB
JavaScript
import {
|
||
ENV,
|
||
MOCK_DATA
|
||
} from './env.js';
|
||
import {
|
||
DialogUtils
|
||
} from '../utils/dialog.js';
|
||
|
||
/**
|
||
* HTTP 拦截器 - 统一处理测试模式和生产模式的请求
|
||
*
|
||
* 核心功能:
|
||
* 1. 测试模式:返回 MOCK_DATA 中定义的模拟数据
|
||
* 2. 生产模式:发起真实的 HTTP 请求到 API 服务器
|
||
* 3. 调试模式:显示请求信息和详细日志
|
||
* 4. 统一的错误处理和响应格式
|
||
*/
|
||
function createHttpInterceptor() {
|
||
return {
|
||
/**
|
||
* 请求前拦截器 - 统一处理 URL 拼接和调试信息
|
||
* @param {string} method - HTTP 方法(GET/POST/DELETE)
|
||
* @param {string} url - API 路径(不包含域名)
|
||
* @param {object} params - 请求参数
|
||
* @param {object} extra - 额外配置(timeout、mockDelay 等)
|
||
* @returns {object} 处理后的请求信息
|
||
*/
|
||
beforeRequest(method, url, params, extra) {
|
||
const fullUrl = ENV.API_URL + url;
|
||
|
||
// URL 调试功能 - 在测试和生产模式下都可用
|
||
if (ENV.DEBUG_URL) {
|
||
// 显示详细的 URL 调试信息
|
||
console.log('HTTP Request Debug:', {
|
||
method,
|
||
fullUrl,
|
||
path: url,
|
||
params,
|
||
isTestMode: ENV.TEST_MODE
|
||
});
|
||
}
|
||
|
||
return {
|
||
fullUrl,
|
||
params,
|
||
extra
|
||
};
|
||
},
|
||
|
||
/**
|
||
* 响应处理器 - 根据模式返回 Mock 数据或真实请求
|
||
* @param {string} method - HTTP 方法
|
||
* @param {string} url - API 路径
|
||
* @param {object} params - 请求参数
|
||
* @param {object} extra - 额外配置
|
||
* @returns {Promise} 统一格式的响应 Promise
|
||
*/
|
||
processResponse(method, url, params, extra) {
|
||
return new Promise((resolve, reject) => {
|
||
// 统一调用前置拦截器(测试模式和生产模式都需要)
|
||
const {
|
||
fullUrl
|
||
} = this.beforeRequest(method, url, params, extra);
|
||
|
||
// 测试模式 - 返回模拟数据
|
||
if (ENV.TEST_MODE && MOCK_DATA[url]) {
|
||
const mockResponse = JSON.parse(JSON.stringify(MOCK_DATA[url])); // 深拷贝避免数据污染
|
||
|
||
// 只在开发环境输出 Mock 日志
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
console.log('测试模式 - 返回模拟数据:', {
|
||
method,
|
||
url,
|
||
response: mockResponse
|
||
});
|
||
}
|
||
|
||
// 模拟网络延迟(让 UI 更贴近真实场景)
|
||
setTimeout(() => {
|
||
resolve(mockResponse);
|
||
}, extra.mockDelay || 500);
|
||
|
||
return;
|
||
}
|
||
|
||
// 生产模式 - 执行真实请求
|
||
// 从本地存储获取认证 token
|
||
const token = uni.getStorageSync('user_token') || '';
|
||
|
||
// 对于 GET 请求,将参数拼接到 URL 查询字符串中
|
||
let requestUrl = fullUrl;
|
||
let requestData;
|
||
|
||
if (method === 'GET') {
|
||
// GET 请求:参数拼接到 URL,body 为空
|
||
if (params && Object.keys(params).length > 0) {
|
||
const queryString = Object.entries(params)
|
||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||
.join('&');
|
||
requestUrl = `${fullUrl}?${queryString}`;
|
||
}
|
||
requestData = undefined;
|
||
} else if (method === 'DELETE') {
|
||
// DELETE 请求:通常不需要 body(资源 ID 在 URL 中)
|
||
requestData = undefined;
|
||
} else {
|
||
// POST/PUT 请求:参数在 body 中
|
||
requestData = params;
|
||
}
|
||
|
||
// 构建请求头
|
||
const headers = {
|
||
'Content-Type': 'application/json',
|
||
'X-App-Version': ENV.VERSION || '1.0.0'
|
||
};
|
||
|
||
// 添加认证头(如果存在 token)
|
||
if (token) {
|
||
headers['Authorization'] = `Bearer ${token}`;
|
||
}
|
||
|
||
uni.request({
|
||
url: requestUrl,
|
||
method: method.toUpperCase(),
|
||
data: requestData,
|
||
header: headers,
|
||
timeout: extra.timeout || 5000,
|
||
sslVerify: ENV.SSL_VERIFY, // SSL 证书验证
|
||
// Android: 由 res/xml/network_security_config.xml 控制
|
||
// iOS: 由 Info.plist 控制
|
||
success: (res) => {
|
||
const response = {
|
||
code: res.statusCode,
|
||
data: res.data,
|
||
message: res.errMsg
|
||
};
|
||
|
||
// 只在开发环境和调试模式下输出响应日志
|
||
if (ENV.DEBUG_URL && process.env.NODE_ENV !== 'production') {
|
||
console.log('生产模式 - 真实请求响应:', {
|
||
method,
|
||
url,
|
||
fullUrl,
|
||
response
|
||
});
|
||
}
|
||
|
||
resolve(response);
|
||
},
|
||
fail: (err) => {
|
||
const errorResponse = {
|
||
code: 500,
|
||
data: null,
|
||
message: err.errMsg || 'network error'
|
||
};
|
||
|
||
// 错误日志在所有环境下都输出(帮助排查问题)
|
||
console.error('请求失败:', {
|
||
method,
|
||
url,
|
||
fullUrl,
|
||
error: errorResponse
|
||
});
|
||
|
||
reject(errorResponse);
|
||
},
|
||
});
|
||
});
|
||
}
|
||
};
|
||
}
|
||
|
||
const httpInterceptor = createHttpInterceptor();
|
||
|
||
/**
|
||
* GET 请求 - 用于查询数据
|
||
* @param {string} url - API 路径(例如:'/wmsServer/wms/api/orderIn/test')
|
||
* @param {object} params - 查询参数(会自动拼接到 URL)
|
||
* @param {object} extra - 额外配置 { timeout, mockDelay }
|
||
* @returns {Promise<{code: number, data: any, message: string}>}
|
||
*
|
||
* @example
|
||
* httpGet('/wmsServer/wms/api/orderIn/getOrderInWithVehicleNo', { vehicleNo: 'V12345' })
|
||
*/
|
||
export async function httpGet(url, params = {}, extra = {}) {
|
||
return httpInterceptor.processResponse('GET', url, params, extra);
|
||
}
|
||
|
||
/**
|
||
* POST 请求 - 用于创建或提交数据
|
||
* @param {string} url - API 路径
|
||
* @param {object} data - 请求体数据
|
||
* @param {object} extra - 额外配置 { timeout, mockDelay }
|
||
* @returns {Promise<{code: number, data: any, message: string}>}
|
||
*
|
||
* @example
|
||
* httpPost('/wmsServer/wms/api/orderIn/loginInBad', { standId: 'EF01', vehicleNo: 'V12345' })
|
||
*/
|
||
export async function httpPost(url, data = {}, extra = {}) {
|
||
return httpInterceptor.processResponse('POST', url, data, extra);
|
||
}
|
||
|
||
/**
|
||
* DELETE 请求 - 用于删除资源
|
||
* 注意:DELETE 请求应该保持完整的 URL(包括资源 ID)
|
||
* Mock 数据匹配时会自动处理路径参数(env.js 中使用基础路径作为 key)
|
||
*
|
||
* @param {string} url - 完整的 API 路径(例如:'/wmsServer/wms/api/orderIn/deleteOrderIn/12345')
|
||
* @param {object} extra - 额外配置 { timeout, mockDelay }
|
||
* @returns {Promise<{code: number, data: any, message: string}>}
|
||
*
|
||
* @example
|
||
* httpDelete('/wmsServer/wms/api/orderIn/deleteOrderIn/12345')
|
||
*
|
||
* 对于测试模式:
|
||
* - 会先尝试匹配完整 URL
|
||
* - 如果找不到,会尝试匹配基础路径(去除末尾数字 ID)
|
||
*/
|
||
export async function httpDelete(url, extra = {}) {
|
||
// 测试模式下,支持基础路径匹配(兼容 env.js 的 MOCK_DATA 定义)
|
||
if (ENV.TEST_MODE) {
|
||
// 先尝试完整 URL 匹配
|
||
if (MOCK_DATA[url]) {
|
||
return httpInterceptor.processResponse('DELETE', url, {}, extra);
|
||
}
|
||
|
||
// 如果找不到,尝试基础路径匹配(移除末尾的数字 ID)
|
||
const cleanUrl = url.split('?')[0]; // 移除查询参数
|
||
const baseUrl = cleanUrl.replace(/\/\d+$/, ''); // 移除末尾数字 ID
|
||
|
||
if (MOCK_DATA[baseUrl]) {
|
||
// 使用基础路径进行 Mock 数据匹配
|
||
return httpInterceptor.processResponse('DELETE', baseUrl, {}, extra);
|
||
}
|
||
}
|
||
|
||
// 生产模式:保持完整的 URL(包括资源 ID)
|
||
return httpInterceptor.processResponse('DELETE', url, {}, extra);
|
||
}
|