aslan-h5/src/utils/http.js

235 lines
6.5 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.

// HTTP请求配置
import { getApiBaseUrl, getCurrentEnv, getUserAuth, isDebugMode } from './env.js'
/**
* 自定义API错误类
*/
class ApiError extends Error {
constructor(message, options = {}) {
super(message)
this.name = 'ApiError'
this.status = options.status || null // HTTP状态码
this.errorCode = options.errorCode || null // 业务错误码 (如: 6010)
this.errorCodeName = options.errorCodeName || null // 错误码名称 (如: "TEAM_NOT_FOUND")
this.errorMsg = options.errorMsg || null // 业务错误消息
this.time = options.time || null // API响应时间戳
this.extValues = options.extValues || null // 扩展值
this.response = options.response || null // 原始响应数据
this.type = options.type || 'unknown' // 错误类型: 'http' | 'business' | 'network'
}
}
const API_BASE_URL = getApiBaseUrl()
const NODE_ENV = getCurrentEnv()
const DEBUG_MODE = isDebugMode()
// 环境信息日志
if (DEBUG_MODE) {
console.log('🌍 Current Environment:', NODE_ENV)
console.log('🔗 API Base URL:', API_BASE_URL)
}
const token = getUserAuth()
// 默认公共请求头配置
let COMMON_HEADERS = {
authorization: `Bearer ${token}`,
'req-app-intel': 'version=1.0.0;build=1;model=SM-G9550;sysVersion=9;channel=Google',
'req-client': 'Android',
'req-imei': '8fa54d728ab449e04f9292329ed44bda',
'req-lang': 'id-ID',
'req-sys-origin': 'origin=LIKEI;originChild=LIKEI',
'req-version': 'V2',
'req-zone': 'Asia/Shanghai',
}
/**
* 更新公共请求头
* @param {object} headers - 要更新的请求头
*/
export function updateCommonHeaders(headers) {
COMMON_HEADERS = {
...COMMON_HEADERS,
...headers,
}
console.debug('🔄 Updated common headers:', COMMON_HEADERS)
}
/**
* 从APP头部信息设置HTTP请求头
* @param {object} headerInfo - APP传递的头部信息
*/
export function setHeadersFromApp(headerInfo) {
const updatedHeaders = {}
// 设置Authorization
if (headerInfo.authorization) {
updatedHeaders.authorization = headerInfo.authorization
}
// 设置语言
if (headerInfo.reqLang) {
updatedHeaders['req-lang'] = headerInfo.reqLang
}
// 设置APP信息
if (headerInfo.appVersion || headerInfo.buildVersion || headerInfo.appChannel) {
const appIntelParts = []
if (headerInfo.appVersion) appIntelParts.push(`version=${headerInfo.appVersion}`)
if (headerInfo.buildVersion) appIntelParts.push(`build=${headerInfo.buildVersion}`)
if (headerInfo.appChannel) appIntelParts.push(`channel=${headerInfo.appChannel}`)
if (appIntelParts.length > 0) {
updatedHeaders['req-app-intel'] = appIntelParts.join(';')
}
}
// 设置设备信息
if (headerInfo.reqImei) {
updatedHeaders['req-imei'] = headerInfo.reqImei
}
// 设置系统来源
if (headerInfo.sysOrigin) {
const sysOriginParts = [`origin=${headerInfo.sysOrigin}`]
if (headerInfo.sysOriginChild) {
sysOriginParts.push(`child=${headerInfo.sysOriginChild}`)
}
updatedHeaders['req-sys-origin'] = sysOriginParts.join(';')
}
updateCommonHeaders(updatedHeaders)
}
// 在http.js中添加导出
export { COMMON_HEADERS, ApiError }
/**
* 通用HTTP请求函数
* @param {string} url - 请求URL
* @param {object} options - 请求选项
* @returns {Promise} - 返回Promise对象
*/
export async function request(url, options = {}) {
const { method = 'GET', data = null, headers = {}, ...otherOptions } = options
const fullUrl = url.startsWith('http') ? url : `${API_BASE_URL}${url}`
const config = {
method,
headers: {
...COMMON_HEADERS,
...headers,
},
...otherOptions,
}
// 如果是POST、PUT等方法且有数据添加body
if (data && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) {
if (data instanceof FormData) {
// FormData类型由浏览器自动设置Content-Type
config.body = data
// 删除手动设置的Content-Type重要
if (config.headers['Content-Type']) {
delete config.headers['Content-Type']
}
} else {
// 非FormData按JSON处理
config.body = JSON.stringify(data)
config.headers['Content-Type'] = 'application/json'
}
}
try {
const response = await fetch(fullUrl, config)
if (!response.ok) {
// 尝试解析响应体获取更多错误信息
let errorData = await response.json()
throw new ApiError(`HTTP Error: ${response.status} ${response.statusText}`, {
type: 'http',
status: response.status,
response: errorData,
errorCode: errorData.errorCode,
errorCodeName: errorData.errorCodeName,
errorMsg: errorData.errorMsg,
time: errorData.time,
})
}
const result = await response.json()
// 检查业务状态
if (result.status === false) {
throw new ApiError(result.errorMsg || result.message || `API Error: ${result.errorCode}`, {
type: 'business',
errorCode: result.errorCode,
errorCodeName: result.errorCodeName,
errorMsg: result.errorMsg,
time: result.time,
extValues: result.extValues,
response: result,
status: response.status,
})
}
return result
} catch (error) {
if (DEBUG_MODE) {
console.error('❌ API Error:', error)
}
// 如果是网络错误或其他未知错误包装成ApiError
if (!(error instanceof ApiError)) {
throw new ApiError(error.message || 'Network or unknown error', {
type: 'network',
originalError: error,
code: 'NETWORK_ERROR',
})
}
throw error
}
}
/**
* GET请求
* @param {string} url - 请求URL
* @param {object} options - 请求选项
* @returns {Promise}
*/
export function get(url, options = {}) {
return request(url, { ...options, method: 'GET' })
}
/**
* POST请求
* @param {string} url - 请求URL
* @param {object} data - 请求数据
* @param {object} options - 请求选项
* @returns {Promise}
*/
export function post(url, data, options = {}) {
return request(url, { ...options, method: 'POST', data })
}
/**
* PUT请求
* @param {string} url - 请求URL
* @param {object} data - 请求数据
* @param {object} options - 请求选项
* @returns {Promise}
*/
export function put(url, data, options = {}) {
return request(url, { ...options, method: 'PUT', data })
}
/**
* DELETE请求
* @param {string} url - 请求URL
* @param {object} options - 请求选项
* @returns {Promise}
*/
export function del(url, options = {}) {
return request(url, { ...options, method: 'DELETE' })
}