Files
sh-app/utils/request.js
T
2026-06-10 17:26:36 +08:00

148 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useUserStore } from '@/store'
// TODO: 替换为实际的 API 地址
export const baseUrl = 'https://sggl.sedin.com.cn/sgglapi/api/'
// ===== 防止重复请求 =====
const pendingRequests = new Map()
/**
* 生成请求唯一标识
*/
function getRequestKey(config) {
const { url = '', method = 'GET', data = {} } = config
const paramStr = JSON.stringify(data)
return `${method}:${url}:${paramStr}`
}
/**
* 检查是否为重复请求
*/
function checkDuplicate(config) {
const key = getRequestKey(config)
if (pendingRequests.has(key)) {
const meta = config.meta || {}
if (meta.toast !== false) {
uni.showToast({ title: '请求过于频繁,请稍后再试', icon: 'none' })
}
return new Error('duplicate request')
}
pendingRequests.set(key, true)
return null
}
/**
* 移除请求标识
*/
function removePending(config) {
const key = getRequestKey(config)
pendingRequests.delete(key)
}
// ========================
// uview-pro 全局请求配置
export const httpRequestConfig = {
baseUrl,
header: {
'content-type': 'application/json'
},
meta: {
originalData: true,
toast: true,
loading: true
}
}
// 全局请求/响应拦截器
export const httpInterceptor = {
request: (config) => {
// 检查重复请求
const dupError = checkDuplicate(config)
if (dupError) throw dupError
const meta = config.meta || {}
if (meta.loading) {
uni.showLoading({ title: '加载中...', mask: true })
}
const userStore = useUserStore()
if (userStore.token) {
config.header.token = userStore.token
}
return config
},
response: (response) => {
const meta = response.config?.meta || {}
if (meta.loading) {
uni.hideLoading()
}
// 请求完成,移除标识
removePending(response.config)
// 根据业务处理错误、例如登录失效等处理接口返回错误码
if (response.data.code !== 1) {
if (meta.toast) {
uni.showToast({
title: response.data.message || '请求失败',
icon: 'none'
})
}
// 401 登录失效,跳转登录页
if (response.data.code === 401) {
const userStore = useUserStore()
userStore.logout()
uni.reLaunch({ url: '/pages/login/index' })
}
throw new Error(response.data.message || '请求失败')
}
uni.showToast({
title: response.data.message || '请求成功',
icon: 'none'
})
return response.data
}
}
/**
* 便捷请求方法(基于 uni.request 封装)
* 也可用 uni.$http.get / uni.$http.postuview-pro
*/
export function request(options) {
return new Promise((resolve, reject) => {
// 运行请求拦截器
const config = { ...httpRequestConfig, ...options }
const finalConfig = httpInterceptor.request({
...config,
header: { ...httpRequestConfig.header, ...options.header }
})
uni.request({
...finalConfig,
url: `${finalConfig.baseUrl}${finalConfig.url}`,
success: (res) => {
try {
const data = httpInterceptor.response({ data: res.data, config: finalConfig })
resolve(data)
} catch (err) {
reject(err)
}
},
fail: (err) => {
removePending(finalConfig) // 网络失败也要清理标识
uni.showToast({ title: '网络连接失败', icon: 'none' })
reject(err)
}
})
})
}
// GET 快捷方法
export function get(url, params = {}) {
return request({ url, method: 'GET', data: params })
}
// POST 快捷方法
export function post(url, data = {}) {
return request({ url, method: 'POST', data })
}