pda-uni-app-perkins/common/http.js
2025-10-31 22:49:51 +08:00

240 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 请求:参数拼接到 URLbody 为空
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);
}