// HTTP请求配置和拦截器 // 基于uView-next的luch-request库实现 import { HTTP_CONFIG, checkApiAuth } from './config.js' /** * 初始化HTTP配置 * @param {Object} vm Vue实例,用于访问vuex等全局状态 */ module.exports = (vm) => { // 初始化请求配置 uni.$u.http.setConfig((config) => { config.baseURL = HTTP_CONFIG.baseURL config.timeout = HTTP_CONFIG.timeout config.header = { 'Content-Type': 'application/json;charset=UTF-8' } return config }) // 请求拦截器 uni.$u.http.interceptors.request.use((config) => { // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{} config.data = config.data || {} config.custom = config.custom || {} // 自动检查接口是否需要鉴权(如果没有明确指定) if (config.custom.auth === undefined) { config.custom.auth = checkApiAuth(config.url) } // 根据custom参数中配置的是否需要token,添加对应的请求头 if (config.custom.auth) { // 从本地存储获取token const token = uni.getStorageSync(HTTP_CONFIG.storageKeys.token) if (token) { config.header.Authorization = `Bearer ${token}` } else { // 如果需要token但没有token,可以跳转到登录页 console.warn('需要token但未找到,请先登录') } } // 根据custom参数配置是否显示loading if (config.custom.loading !== false) { uni.showLoading({ title: config.custom.loadingText || '请稍候...', mask: true }) } return config }, config => { // 请求错误处理 return Promise.reject(config) }) // 响应拦截器 uni.$u.http.interceptors.response.use((response) => { /* 对响应成功做点什么 可使用async await 做异步操作*/ // 隐藏loading uni.hideLoading() const data = response.data const custom = response.config?.custom // 统一的响应数据处理 if (data.code !== undefined) { // 如果服务端返回的状态码不等于200,则reject() if (data.code !== 200) { // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示 if (custom?.toast !== false) { uni.$u.toast(data.message || '请求失败') } // 特殊状态码处理 if (data.code === 401) { // token过期,清除本地token并跳转到登录页 uni.removeStorageSync(HTTP_CONFIG.storageKeys.token) uni.removeStorageSync(HTTP_CONFIG.storageKeys.refreshToken) uni.removeStorageSync(HTTP_CONFIG.storageKeys.userInfo) uni.reLaunch({ url: HTTP_CONFIG.loginPage }) return Promise.reject(data) } // 如果需要catch返回,则进行reject if (custom?.catch) { return Promise.reject(data) } else { // 否则返回一个pending中的promise,请求不会进入catch中 return new Promise(() => {}) } } } // 返回处理后的数据 return data.data !== undefined ? data.data : data }, (response) => { /* 对响应错误做点什么 (statusCode !== 200)*/ // 隐藏loading uni.hideLoading() const custom = response.config?.custom // 网络错误处理 let errorMessage = '网络错误,请检查网络连接' if (response.statusCode) { switch (response.statusCode) { case 400: errorMessage = '请求参数错误' break case 401: errorMessage = '未授权,请重新登录' // 清除本地认证信息 uni.removeStorageSync(HTTP_CONFIG.storageKeys.token) uni.removeStorageSync(HTTP_CONFIG.storageKeys.refreshToken) uni.removeStorageSync(HTTP_CONFIG.storageKeys.userInfo) // 跳转到登录页 uni.reLaunch({ url: HTTP_CONFIG.loginPage }) break case 403: errorMessage = '拒绝访问' break case 404: errorMessage = '请求地址不存在' break case 500: errorMessage = '服务器内部错误' break case 502: errorMessage = '网关错误' break case 503: errorMessage = '服务不可用' break case 504: errorMessage = '网关超时' break default: errorMessage = `连接错误${response.statusCode}` } } // 显示错误提示 if (custom?.toast !== false) { uni.$u.toast(errorMessage) } console.error('请求错误:', response) return Promise.reject(response) }) }