/**
|
* 公共请求方法封装(用户端小程序)
|
* 统一处理:地址拼接、token 注入、响应解包、异常提示、登录失效跳转
|
*/
|
import config from '@/config/index.js'
|
|
// 登录失效提示开关:防止多个并发请求同时弹窗
|
let isReloginTipShowing = false
|
|
// ======================== 登录令牌读写 ========================
|
|
/** 读取本地缓存的 token */
|
export function getToken() {
|
return uni.getStorageSync(config.tokenKey) || ''
|
}
|
|
/** 写入 token 到本地缓存 */
|
export function setToken(token) {
|
uni.setStorageSync(config.tokenKey, token)
|
}
|
|
/** 清除本地登录态 */
|
export function clearToken() {
|
uni.removeStorageSync(config.tokenKey)
|
}
|
|
// ======================== 核心请求方法 ========================
|
|
/**
|
* 统一请求方法
|
* @param {Object} options 请求配置
|
* @param {String} options.url 接口路径(不含根地址;传完整 http 地址则直接使用)
|
* @param {String} [options.method] 请求方法,默认 GET
|
* @param {Object} [options.data] 请求参数
|
* @param {Object} [options.header] 自定义请求头
|
* @param {Boolean} [options.auth] 是否需要携带 token,默认 true
|
* @param {Boolean} [options.loading] 是否显示加载中提示,默认 false
|
* @param {String} [options.loadingText] 加载提示文案
|
* @returns {Promise<Object>} 解析后的响应体 { code, msg, data }
|
*/
|
export function request(options = {}) {
|
const {
|
url = '',
|
method = 'GET',
|
data = {},
|
header = {},
|
auth = true,
|
loading = false,
|
loadingText = '加载中...'
|
} = options
|
|
// 拼接完整请求地址
|
const fullUrl = /^https?:\/\//i.test(url) ? url : config.baseUrl + url
|
|
// 组装请求头
|
const finalHeader = {
|
'Content-Type': 'application/json;charset=utf-8',
|
...header
|
}
|
// 鉴权接口自动注入 token
|
const token = getToken()
|
if (auth && token) {
|
finalHeader.Authorization = 'Bearer ' + token
|
}
|
|
if (loading) {
|
uni.showLoading({ title: loadingText, mask: true })
|
}
|
|
return new Promise((resolve, reject) => {
|
uni.request({
|
url: fullUrl,
|
method: method.toUpperCase(),
|
data,
|
header: finalHeader,
|
timeout: config.timeout,
|
success: (res) => {
|
const { statusCode, data: body } = res
|
|
// 非 HTTP 200 视为网络异常
|
if (statusCode !== 200) {
|
reject(new Error('网络请求异常:' + statusCode))
|
return
|
}
|
|
// 登录失效:清理登录态并跳转登录页
|
if (body && body.code === config.unauthorizedCode) {
|
_handleUnauthorized()
|
reject(new Error(body.msg || '登录状态已过期'))
|
return
|
}
|
|
// 业务成功:返回完整响应体,调用方按需取 data
|
if (body && body.code === config.successCode) {
|
resolve(body)
|
return
|
}
|
|
// 业务失败:统一抛出错误信息
|
reject(new Error((body && body.msg) || '请求失败'))
|
},
|
fail: (err) => {
|
reject(new Error((err && err.errMsg) || '网络连接失败'))
|
},
|
complete: () => {
|
if (loading) {
|
uni.hideLoading()
|
}
|
}
|
})
|
})
|
}
|
|
/**
|
* 处理登录态失效:清缓存 + 提示 + 延时跳转登录页
|
*/
|
function _handleUnauthorized() {
|
if (isReloginTipShowing) return
|
isReloginTipShowing = true
|
clearToken()
|
uni.showToast({ title: '登录状态已过期,请重新登录', icon: 'none' })
|
setTimeout(() => {
|
isReloginTipShowing = false
|
uni.reLaunch({ url: config.loginPage })
|
}, 1500)
|
}
|
|
// ======================== 快捷方法 ========================
|
|
/** GET 请求 */
|
export const get = (url, data = {}, options = {}) =>
|
request({ url, method: 'GET', data, ...options })
|
|
/** POST 请求 */
|
export const post = (url, data = {}, options = {}) =>
|
request({ url, method: 'POST', data, ...options })
|
|
/** PUT 请求 */
|
export const put = (url, data = {}, options = {}) =>
|
request({ url, method: 'PUT', data, ...options })
|
|
/** DELETE 请求 */
|
export const del = (url, data = {}, options = {}) =>
|
request({ url, method: 'DELETE', data, ...options })
|
|
export default request
|