import Auth from './auth'; // 服务器地址 const BASE_URL = process.env.VUE_APP_BASE_API || 'http://yishi.com'; // 请求超时时间 const TIMEOUT = 10000; /** * 请求拦截器 * @param {Object} config 请求配置 * @returns {Object} 处理后的请求配置 */ function requestInterceptor(config) { // 获取 token const token = uni.getStorageSync('token'); // 如果有 token,则带上请求头 Authorization: Bearer + token if (token) { config.header = { ...config.header, 'Authorization': `Bearer ${token}` }; } // 打印请求日志 console.log('请求地址:', `${config.baseURL || BASE_URL}${config.url}`); return config; } /** * 响应拦截器 * @param {Object} response 响应数据 * @returns {Object|Promise} 处理后的响应数据或Promise */ function responseInterceptor(response) { // 未登录或token失效 - 取消登录拦截 if (response.data.code === 401) { console.log('登录已过期,需要重新登录'); // 清除登录信息 Auth.removeToken(); Auth.removeUserInfo(); // 跳转到登录页 uni.reLaunch({ url: '/pages/login/index' }); return Promise.reject(new Error('登录已过期,请重新登录')); } // token需要刷新 - 410 状态码 if (response.data.code === 410) { // 尝试刷新 token return Auth.refreshToken() .then(res => { if (res.code === 200) { // 更新本地token Auth.setToken(res.data.token, res.data.token_expired - Math.floor(Date.now() / 1000)); // 使用新token重试原请求 const config = response.config; config.header.Authorization = `Bearer ${res.data.token}`; // 重新发起请求 return request(config); } else { // 刷新失败,跳转到登录页 uni.reLaunch({ url: '/pages/login/index' }); return Promise.reject(new Error('登录已过期,请重新登录')); } }) .catch(err => { console.error('刷新token失败', err); // 清除登录信息 Auth.removeToken(); Auth.removeUserInfo(); // 跳转到登录页 uni.reLaunch({ url: '/pages/login/index' }); return Promise.reject(new Error('登录已过期,请重新登录')); }); } return response.data; } /** * 构建完整的URL,包括查询参数 * @param {string} baseUrl 基础URL * @param {Object} params 查询参数 * @returns {string} 完整的URL */ function buildUrlWithParams(baseUrl, params) { if (!params || Object.keys(params).length === 0) { return baseUrl; } const queryString = Object.keys(params) .filter(key => params[key] !== undefined && params[key] !== null) .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) .join('&'); return queryString ? `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${queryString}` : baseUrl; } /** * 统一请求函数 * @param {Object} options 请求选项 * @returns {Promise} 请求结果 */ function request(options) { // 合并请求选项 const config = { baseURL: BASE_URL, timeout: TIMEOUT, header: { 'Content-Type': 'application/json' }, ...options }; // 请求拦截 const interceptedConfig = requestInterceptor(config); // 处理GET请求参数 let url = `${interceptedConfig.baseURL}${interceptedConfig.url}`; const method = interceptedConfig.method || 'GET'; // 如果是GET请求并且有params参数,将其转换为URL查询字符串 if (method.toUpperCase() === 'GET' && interceptedConfig.params) { url = buildUrlWithParams(url, interceptedConfig.params); // 打印完整请求URL(便于调试) console.log('完整请求URL:', url); } // 发起请求 return new Promise((resolve, reject) => { uni.request({ url: url, method: method, data: method.toUpperCase() === 'GET' ? undefined : interceptedConfig.data, header: interceptedConfig.header, timeout: interceptedConfig.timeout, success: (res) => { try { const result = responseInterceptor(res); resolve(result); } catch (error) { reject(error); } }, fail: (err) => { // 显示提示 uni.showToast({ title: '网络请求失败', icon: 'none', duration: 2000 }); // 增强错误对象,添加更多信息便于调试 const enhancedError = { ...err, url: url, method: method, params: method.toUpperCase() === 'GET' ? interceptedConfig.params : undefined, data: method.toUpperCase() === 'GET' ? undefined : interceptedConfig.data, message: err.errMsg || '网络请求失败' }; console.error('请求失败详情:', enhancedError); reject(enhancedError); } }); }); } export default request;