pet/http/config/request.js

174 lines
4.4 KiB
JavaScript
Raw Permalink 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请求配置和拦截器
// 基于uView-next的luch-request库实现
import { HTTP_CONFIG, checkApiAuth, checkAuthRequiredApi } from './config.js'
import { clearAuthData, isUserLoggedIn, handleAuthRequired, tryAutoLogin } from '../utils/auth-helper.js'
/**
* 初始化HTTP配置
* @param {Object} vm Vue实例用于访问vuex等全局状态
*/
export default (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)
}
// 检查是否为需要强制登录的接口
const isAuthRequiredApi = checkAuthRequiredApi(config.url)
// 如果是需要强制登录的接口,检查登录状态
if (isAuthRequiredApi) {
if (!isUserLoggedIn()) {
console.log('访问需要鉴权的接口但未完成登录,跳转到登录流程:', config.url)
handleAuthRequired()
return Promise.reject({
message: '需要登录',
code: 'AUTH_REQUIRED',
url: config.url
})
}
}
// 添加Authorization请求头
if (config.custom.auth !== false) {
const token = uni.getStorageSync(HTTP_CONFIG.storageKeys.token)
if (token) {
config.header.Authorization = `Bearer ${token}`
}
}
// 根据custom参数配置是否显示loading
if (config.custom.loading !== false) {
uni.showLoading({
title: config.custom.loadingText || '请稍候...',
mask: true
})
}
return config
}, config => {
// 请求错误处理
// 如果是AUTH_REQUIRED错误不显示loading
if (config.code === 'AUTH_REQUIRED') {
// 不显示loading因为会跳转页面
return Promise.reject(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) {
// 如果服务端返回的状态码不等于0成功则reject()
if (data.code !== 0) {
// 如果没有显式定义custom的toast参数为false的话默认对报错进行toast弹出提示
if (custom?.toast !== false) {
uni.$u.toast(data.message || '请求失败')
}
// 特殊状态码处理
if (data.code === 401) {
// token过期清除本地认证信息并跳转到登录流程
clearAuthData()
handleAuthRequired()
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 = '未授权,请重新登录'
clearAuthData()
handleAuthRequired()
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)
})
}