280 lines
6.5 KiB
JavaScript
280 lines
6.5 KiB
JavaScript
/**
|
||
* 统一的 HTTP 请求封装
|
||
* 自动添加 tenantId、token 等公共参数
|
||
*/
|
||
|
||
import { getApiUrl, getApiEnv } from './config.js'
|
||
|
||
/**
|
||
* 获取 tenantId(从本地存储)
|
||
*/
|
||
function getTenantId() {
|
||
try {
|
||
return uni.getStorageSync('backend-tenant-id') || ''
|
||
} catch (e) {
|
||
console.error('获取 tenantId 失败:', e)
|
||
return ''
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 跳转到登录页面
|
||
*/
|
||
function redirectToLogin() {
|
||
const loginPage = '/uni_modules/uni-id-pages/pages/login/login-withpwd'
|
||
const pages = getCurrentPages()
|
||
|
||
// 如果当前已经在登录页,不重复跳转
|
||
if (pages.length > 0) {
|
||
const currentPage = pages[pages.length - 1]
|
||
if (currentPage.route && currentPage.route.includes('login')) {
|
||
return
|
||
}
|
||
}
|
||
|
||
uni.reLaunch({
|
||
url: loginPage,
|
||
fail: (err) => {
|
||
console.error('跳转登录页失败:', err)
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 检查是否为登录相关接口(不需要租户ID的接口)
|
||
*/
|
||
function isLoginApi(url) {
|
||
if (!url) return false
|
||
// 登录接口不需要租户ID
|
||
return url.includes('/api/sys/auth/login')
|
||
}
|
||
|
||
/**
|
||
* 获取 token(从本地存储)
|
||
*/
|
||
function getToken() {
|
||
try {
|
||
return uni.getStorageSync('backend-token') || ''
|
||
} catch (e) {
|
||
console.error('获取 token 失败:', e)
|
||
return ''
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取 roleName(从本地存储)
|
||
*/
|
||
function getRoleName() {
|
||
try {
|
||
return uni.getStorageSync('backend-role-name') || ''
|
||
} catch (e) {
|
||
console.error('获取 roleName 失败:', e)
|
||
return ''
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取 scenario(从本地存储)
|
||
*/
|
||
function getScenario() {
|
||
try {
|
||
return uni.getStorageSync('backend-scenario') || ''
|
||
} catch (e) {
|
||
console.error('获取 scenario 失败:', e)
|
||
return ''
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 统一的请求方法
|
||
* @param {Object} options - uni.request 的配置选项
|
||
* @param {string} options.url - 请求地址(会自动使用 getApiUrl 处理)
|
||
* @param {string} options.method - 请求方法,默认 'GET'
|
||
* @param {Object} options.data - 请求数据
|
||
* @param {Object} options.header - 请求头(会自动合并公共 header)
|
||
* @param {number} options.timeout - 超时时间
|
||
* @param {boolean} options.needTenantId - 是否需要添加 tenantId,默认 true
|
||
* @param {boolean} options.needToken - 是否需要添加 token,默认 true
|
||
* @returns {Promise} 请求结果
|
||
*/
|
||
export function request(options = {}) {
|
||
const {
|
||
url,
|
||
method = 'GET',
|
||
data = {},
|
||
header = {},
|
||
timeout = 10000,
|
||
needTenantId = true,
|
||
needToken = true,
|
||
...restOptions
|
||
} = options
|
||
|
||
// 处理 URL(自动添加 baseUrl)
|
||
const fullUrl = url.startsWith('http') ? url : getApiUrl(url)
|
||
const apiEnv = typeof getApiEnv === 'function' ? getApiEnv() : ''
|
||
|
||
// 详细的请求日志
|
||
console.log('[Request] 开始处理请求:', {
|
||
originalUrl: url,
|
||
fullUrl: fullUrl,
|
||
method: method.toUpperCase(),
|
||
isLoginApi: isLoginApi(fullUrl),
|
||
apiEnv: apiEnv,
|
||
needTenantId,
|
||
needToken
|
||
})
|
||
|
||
// 每次请求打印完整 URL,格式示例:
|
||
// H5环境(local)直接使用完整URL: http://localhost:8090/api/audioManagement/list
|
||
console.log(`[Request] 完整请求URL: ${fullUrl}`)
|
||
|
||
// 构建请求头
|
||
const requestHeader = {
|
||
'Content-Type': 'application/json',
|
||
...header
|
||
}
|
||
|
||
// 每次请求都自动添加 token(登录接口除外)
|
||
// 确保所有后端请求都携带 token 进行身份验证
|
||
if (needToken && !isLoginApi(fullUrl)) {
|
||
const token = getToken()
|
||
if (token) {
|
||
// 每次请求都添加 token 到 Authorization header
|
||
requestHeader['Authorization'] = `Bearer ${token}`
|
||
} else {
|
||
// 如果没有 token,移除可能存在的旧 Authorization header
|
||
delete requestHeader['Authorization']
|
||
}
|
||
}
|
||
|
||
// 添加 roleName 和 scenario 到 header(从登录响应中获取)
|
||
const roleName = getRoleName()
|
||
if (roleName) {
|
||
requestHeader['X-Role-Name'] = roleName
|
||
}
|
||
const scenario = getScenario()
|
||
if (scenario) {
|
||
requestHeader['X-Scenario'] = scenario
|
||
}
|
||
|
||
// 处理请求数据
|
||
let requestData = { ...data }
|
||
|
||
// 添加 tenantId 到 X-Tenant-Id header
|
||
// 技术方案:登录返回的 LoginResponse 中包含 tenantId,前端保存后自动添加到所有请求的 header 中
|
||
if (needTenantId) {
|
||
const tenantId = getTenantId()
|
||
|
||
// 检查是否需要登录:如果不是登录接口且租户ID为空,则跳转到登录页
|
||
if (!isLoginApi(fullUrl) && !tenantId) {
|
||
console.warn('[Request] 租户ID为空,跳转到登录页面')
|
||
redirectToLogin()
|
||
// 返回一个被拒绝的Promise,阻止请求继续执行
|
||
return Promise.reject(new Error('未登录,请先登录'))
|
||
}
|
||
|
||
if (tenantId) {
|
||
// 将 tenantId 放入 X-Tenant-Id header(适用于所有请求类型:GET、POST、PUT、DELETE)
|
||
requestHeader['X-Tenant-Id'] = tenantId
|
||
}
|
||
}
|
||
|
||
// 发起请求
|
||
console.log('[Request] 准备发起 uni.request:', {
|
||
url: fullUrl,
|
||
method: method.toUpperCase(),
|
||
hasData: !!requestData,
|
||
hasHeaders: !!requestHeader,
|
||
timeout: timeout
|
||
})
|
||
|
||
return new Promise((resolve, reject) => {
|
||
console.log('[Request] 调用 uni.request 开始执行')
|
||
uni.request({
|
||
url: fullUrl,
|
||
method: method.toUpperCase(),
|
||
data: requestData,
|
||
header: requestHeader,
|
||
timeout,
|
||
...restOptions,
|
||
success: (res) => {
|
||
console.log('[Request] 收到响应:', {
|
||
url: fullUrl,
|
||
method: method.toUpperCase(),
|
||
statusCode: res.statusCode,
|
||
hasData: !!res.data,
|
||
dataType: typeof res.data
|
||
})
|
||
|
||
// 检查HTTP状态码,如果是401(未授权),跳转到登录页面
|
||
if (res.statusCode === 401) {
|
||
console.warn('[Request] 收到401状态码,跳转到登录页面')
|
||
redirectToLogin()
|
||
reject(new Error('登录已过期,请重新登录'))
|
||
return
|
||
}
|
||
resolve(res)
|
||
},
|
||
fail: (err) => {
|
||
console.error('[Request] 请求失败:', {
|
||
url: fullUrl,
|
||
method: method.toUpperCase(),
|
||
error: err,
|
||
errorMessage: err.errMsg || '未知错误',
|
||
errorCode: err.code || '无错误码'
|
||
})
|
||
reject(err)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
/**
|
||
* GET 请求快捷方法
|
||
*/
|
||
export function get(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'GET',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
/**
|
||
* POST 请求快捷方法
|
||
*/
|
||
export function post(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'POST',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
/**
|
||
* PUT 请求快捷方法
|
||
*/
|
||
export function put(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'PUT',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
/**
|
||
* DELETE 请求快捷方法
|
||
*/
|
||
export function del(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'DELETE',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|