// 统一请求层:封装 baseUrl、自动带 token、解析后端 RESTful 响应、401 处理 import { BASE_URL, REQUEST_TIMEOUT, TOKEN_KEY, MEMBER_KEY, LOGIN_PAGE } from '@/utils/config' // token 失效对应的业务码(沿用管理端约定) const TOKEN_INVALID_CODES = [401, 600, 601, 602] let redirecting = false function clearAuthStorage() { uni.removeStorageSync(TOKEN_KEY) uni.removeStorageSync(MEMBER_KEY) } function redirectToLogin() { clearAuthStorage() if (redirecting) return redirecting = true uni.reLaunch({ url: LOGIN_PAGE, complete: () => { setTimeout(() => { redirecting = false }, 800) } }) } function toast(message) { uni.showToast({ title: message || '请求出错,请重试', icon: 'none' }) } /** * 发起请求 * @param {Object} options * @param {String} options.url 接口路径(含 api/ 前缀) * @param {String} options.method GET/POST/PUT/DELETE * @param {Object} options.data 参数(GET 也放 data,会作为 query) * @param {Object} options.header 自定义请求头 * @param {Boolean} options.auth 是否需要携带 token(默认 true) * @param {Boolean} options.loading 是否显示 loading(默认 false) * @param {Boolean} options.silent 出错时是否静默(不弹 toast,默认 false) * @returns {Promise} resolve 后端 data 字段 */ export default function request(options = {}) { const { url, method = 'GET', data = {}, header = {}, auth = true, loading = false, silent = false } = options return new Promise((resolve, reject) => { if (loading) { uni.showLoading({ title: '加载中', mask: true }) } const finalHeader = { 'content-type': 'application/json', ...header } const token = uni.getStorageSync(TOKEN_KEY) if (auth && token) { // token 存储时已含 "Bearer ",做一次兜底 finalHeader['Authorization'] = String(token).indexOf('Bearer') === 0 ? token : ('Bearer ' + token) } uni.request({ url: BASE_URL + url, method: String(method).toUpperCase(), data, header: finalHeader, timeout: REQUEST_TIMEOUT, success: (res) => { const statusCode = res.statusCode const body = res.data || {} // HTTP 401 未授权 if (statusCode === 401) { redirectToLogin() reject(new Error('未登录或登录已过期')) return } // 非 2xx if (statusCode < 200 || statusCode >= 300) { const msg = body && body.msg ? body.msg : `请求失败(${statusCode})` if (!silent) toast(msg) reject(new Error(msg)) return } // 后端 RESTful 响应:{ code, msg, data } const code = body.code if (code === undefined || code === null) { // 无标准包裹(极少数接口),直接返回原始 body resolve(body) return } if (code === 200) { resolve(body.data !== undefined ? body.data : null) return } if (TOKEN_INVALID_CODES.indexOf(code) > -1) { redirectToLogin() reject(new Error(body.msg || '登录已过期')) return } if (!silent) toast(body.msg) reject(new Error(body.msg || '请求出错')) }, fail: (err) => { if (!silent) toast('网络异常,请稍后重试') reject(err) }, complete: () => { if (loading) uni.hideLoading() } }) }) }