1
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
// HTTP模块配置文件
|
||||
|
||||
/**
|
||||
* 环境配置
|
||||
*/
|
||||
const ENV_CONFIG = {
|
||||
// 开发环境
|
||||
development: {
|
||||
baseURL: 'https://dev-api.pet-ai.com',
|
||||
timeout: 30000
|
||||
},
|
||||
// 测试环境
|
||||
testing: {
|
||||
baseURL: 'https://test-api.pet-ai.com',
|
||||
timeout: 30000
|
||||
},
|
||||
// 生产环境
|
||||
production: {
|
||||
baseURL: 'https://api.pet-ai.com',
|
||||
timeout: 60000
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前环境 (可根据实际情况动态设置)
|
||||
*/
|
||||
let CURRENT_ENV = 'development' // development | testing | production
|
||||
|
||||
/**
|
||||
* HTTP基础配置
|
||||
*/
|
||||
export const HTTP_CONFIG = {
|
||||
// 当前环境配置
|
||||
...ENV_CONFIG[CURRENT_ENV],
|
||||
|
||||
// 登录页面路径
|
||||
loginPage: '/pages/login/login',
|
||||
|
||||
// 存储键名配置
|
||||
storageKeys: {
|
||||
token: 'token',
|
||||
refreshToken: 'refreshToken',
|
||||
userInfo: 'userInfo'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不需要鉴权的接口列表
|
||||
* 注意:只需要配置不需要token的接口,其他接口默认都需要鉴权
|
||||
*/
|
||||
export const NO_AUTH_APIS = [
|
||||
// 用户认证相关
|
||||
'/auth/login',
|
||||
'/auth/register',
|
||||
'/auth/wx-login',
|
||||
'/auth/refresh',
|
||||
|
||||
// 公开浏览的接口
|
||||
'/ai/knowledge', // AI知识库
|
||||
'/adoption/pets', // 浏览待领养宠物
|
||||
'/adoption/pets/search', // 搜索宠物
|
||||
'/adoption/pets/filter', // 筛选宠物
|
||||
'/adoption/organizations', // 领养机构列表
|
||||
'/reviews', // 查看评价
|
||||
'/system/config', // 系统配置
|
||||
'/system/version', // 版本信息
|
||||
'/system/check-update', // 检查更新
|
||||
'/sms/send', // 发送短信验证码
|
||||
'/sms/verify', // 验证短信验证码
|
||||
'/common/regions' // 地区数据
|
||||
]
|
||||
|
||||
/**
|
||||
* 检查接口是否需要鉴权
|
||||
* @param {String} url 接口URL
|
||||
* @returns {Boolean} 是否需要鉴权
|
||||
*/
|
||||
export function checkApiAuth(url) {
|
||||
// 移除查询参数,只保留路径
|
||||
const path = url.split('?')[0]
|
||||
|
||||
// 检查是否在不需要鉴权的列表中
|
||||
for (const noAuthApi of NO_AUTH_APIS) {
|
||||
// 支持通配符匹配
|
||||
if (noAuthApi.includes('*')) {
|
||||
const regex = new RegExp('^' + noAuthApi.replace(/\*/g, '.*') + '$')
|
||||
if (regex.test(path)) {
|
||||
return false
|
||||
}
|
||||
} else if (path === noAuthApi || path.startsWith(noAuthApi + '/')) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 默认需要鉴权
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加不需要鉴权的接口
|
||||
* @param {String|Array} apis 接口路径或接口路径数组
|
||||
*/
|
||||
export function addNoAuthApis(apis) {
|
||||
if (Array.isArray(apis)) {
|
||||
NO_AUTH_APIS.push(...apis)
|
||||
} else {
|
||||
NO_AUTH_APIS.push(apis)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前环境
|
||||
* @param {String} env 环境名称 (development | testing | production)
|
||||
*/
|
||||
export function setEnvironment(env) {
|
||||
if (ENV_CONFIG[env]) {
|
||||
CURRENT_ENV = env
|
||||
// 更新HTTP配置
|
||||
Object.assign(HTTP_CONFIG, ENV_CONFIG[env])
|
||||
console.log(`HTTP环境已切换到: ${env}`)
|
||||
console.log(`当前baseURL: ${HTTP_CONFIG.baseURL}`)
|
||||
} else {
|
||||
console.error(`无效的环境名称: ${env}`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// HTTP请求配置和拦截器
|
||||
// 基于uView-next的luch-request库实现
|
||||
|
||||
import { HTTP_CONFIG, checkApiAuth } from './config.js'
|
||||
|
||||
/**
|
||||
* 初始化HTTP配置
|
||||
* @param {Object} vm Vue实例,用于访问vuex等全局状态
|
||||
*/
|
||||
module.exports = (vm) => {
|
||||
// 初始化请求配置
|
||||
uni.$u.http.setConfig((config) => {
|
||||
config.baseURL = HTTP_CONFIG.baseURL
|
||||
config.timeout = HTTP_CONFIG.timeout
|
||||
config.header = {
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
uni.$u.http.interceptors.request.use((config) => {
|
||||
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
|
||||
config.data = config.data || {}
|
||||
config.custom = config.custom || {}
|
||||
|
||||
// 自动检查接口是否需要鉴权(如果没有明确指定)
|
||||
if (config.custom.auth === undefined) {
|
||||
config.custom.auth = checkApiAuth(config.url)
|
||||
}
|
||||
|
||||
// 根据custom参数中配置的是否需要token,添加对应的请求头
|
||||
if (config.custom.auth) {
|
||||
// 从本地存储获取token
|
||||
const token = uni.getStorageSync('token')
|
||||
if (token) {
|
||||
config.header.Authorization = `Bearer ${token}`
|
||||
} else {
|
||||
// 如果需要token但没有token,可以跳转到登录页
|
||||
console.warn('需要token但未找到,请先登录')
|
||||
}
|
||||
}
|
||||
|
||||
// 根据custom参数配置是否显示loading
|
||||
if (config.custom.loading !== false) {
|
||||
uni.showLoading({
|
||||
title: config.custom.loadingText || '请稍候...',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
|
||||
return config
|
||||
}, config => {
|
||||
// 请求错误处理
|
||||
return Promise.reject(config)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
uni.$u.http.interceptors.response.use((response) => {
|
||||
/* 对响应成功做点什么 可使用async await 做异步操作*/
|
||||
|
||||
// 隐藏loading
|
||||
uni.hideLoading()
|
||||
|
||||
const data = response.data
|
||||
const custom = response.config?.custom
|
||||
|
||||
// 统一的响应数据处理
|
||||
if (data.code !== undefined) {
|
||||
// 如果服务端返回的状态码不等于200,则reject()
|
||||
if (data.code !== 200) {
|
||||
// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
|
||||
if (custom?.toast !== false) {
|
||||
uni.$u.toast(data.message || '请求失败')
|
||||
}
|
||||
|
||||
// 特殊状态码处理
|
||||
if (data.code === 401) {
|
||||
// token过期,清除本地token并跳转到登录页
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('refreshToken')
|
||||
uni.removeStorageSync('userInfo')
|
||||
uni.reLaunch({
|
||||
url: HTTP_CONFIG.loginPage
|
||||
})
|
||||
return Promise.reject(data)
|
||||
}
|
||||
|
||||
// 如果需要catch返回,则进行reject
|
||||
if (custom?.catch) {
|
||||
return Promise.reject(data)
|
||||
} else {
|
||||
// 否则返回一个pending中的promise,请求不会进入catch中
|
||||
return new Promise(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回处理后的数据
|
||||
return data.data !== undefined ? data.data : data
|
||||
}, (response) => {
|
||||
/* 对响应错误做点什么 (statusCode !== 200)*/
|
||||
|
||||
// 隐藏loading
|
||||
uni.hideLoading()
|
||||
|
||||
const custom = response.config?.custom
|
||||
|
||||
// 网络错误处理
|
||||
let errorMessage = '网络错误,请检查网络连接'
|
||||
|
||||
if (response.statusCode) {
|
||||
switch (response.statusCode) {
|
||||
case 400:
|
||||
errorMessage = '请求参数错误'
|
||||
break
|
||||
case 401:
|
||||
errorMessage = '未授权,请重新登录'
|
||||
// 清除本地认证信息
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('refreshToken')
|
||||
uni.removeStorageSync('userInfo')
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: HTTP_CONFIG.loginPage
|
||||
})
|
||||
break
|
||||
case 403:
|
||||
errorMessage = '拒绝访问'
|
||||
break
|
||||
case 404:
|
||||
errorMessage = '请求地址不存在'
|
||||
break
|
||||
case 500:
|
||||
errorMessage = '服务器内部错误'
|
||||
break
|
||||
case 502:
|
||||
errorMessage = '网关错误'
|
||||
break
|
||||
case 503:
|
||||
errorMessage = '服务不可用'
|
||||
break
|
||||
case 504:
|
||||
errorMessage = '网关超时'
|
||||
break
|
||||
default:
|
||||
errorMessage = `连接错误${response.statusCode}`
|
||||
}
|
||||
}
|
||||
|
||||
// 显示错误提示
|
||||
if (custom?.toast !== false) {
|
||||
uni.$u.toast(errorMessage)
|
||||
}
|
||||
|
||||
console.error('请求错误:', response)
|
||||
return Promise.reject(response)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user