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); }