This commit is contained in:
2026-09-13 02:28:46 +08:00
parent df5492a48a
commit 42f9530a59
27 changed files with 979 additions and 149 deletions
+29 -10
View File
@@ -1,5 +1,9 @@
import { BASE_URL, API_PREFIX, ERROR_MESSAGES } from './config'
import * as auth from './auth'
import { logger } from './logger'
// 日志模块名
const LOG = 'request'
// 业务错误对象(携带 code,页面可按 code 定制处理)
export class ApiError extends Error {
@@ -44,12 +48,12 @@ function isAuthExpiredCode(code: number, statusCode?: number): boolean {
// 登录失效后的收尾:非关键请求只 reject,不动登录态
function failAuth(code: number, msg: string, silentAuth: boolean, showError: boolean) {
if (!silentAuth) {
console.log('[auth] failAuth 清理登录态并跳转登录页, code=', code, 'msg=', msg)
logger.warn(LOG, '登录态失效,清理 token 并跳转登录页, code=', code, 'msg=', msg)
auth.clearTokens()
handleAuthExpired()
if (showError) showToast('登录已过期,请重新登录')
} else {
console.log('[auth] failAuth 静默失败(不动登录态), code=', code)
logger.warn(LOG, '登录态失效但静默处理(不动登录态), code=', code)
}
return new ApiError(code, msg || '登录已过期')
}
@@ -69,11 +73,11 @@ function doRefresh(): Promise<boolean> {
const refreshToken = auth.getRefreshToken()
const accessToken = auth.getAccessToken()
if (!refreshToken || !accessToken) {
console.log('[auth] doRefresh 无 token,放弃刷新')
logger.warn(LOG, 'doRefresh 缺少 refresh/access token,放弃刷新')
resolve(false)
return
}
console.log('[auth] doRefresh 发起刷新')
logger.debug(LOG, 'doRefresh 发起刷新')
wx.request({
url: `${BASE_URL}${API_PREFIX}/user/refresh-token`,
method: 'POST',
@@ -88,15 +92,15 @@ function doRefresh(): Promise<boolean> {
refreshToken: body.data.refresh_token,
expireTime: body.data.expire_time,
})
console.log('[auth] doRefresh 成功')
logger.debug(LOG, 'doRefresh 成功')
resolve(true)
} else {
console.log('[auth] doRefresh 响应异常, code=', body && body.code)
logger.error(LOG, 'doRefresh 响应异常, code=', body && body.code)
resolve(false)
}
},
fail: () => {
console.log('[auth] doRefresh 网络失败')
logger.error(LOG, 'doRefresh 网络失败')
resolve(false)
},
})
@@ -127,17 +131,17 @@ let redirecting = false
*/
export function redirectToLogin(): void {
if (redirecting) {
console.log('[auth] redirectToLogin 幂等锁生效,丢弃本次跳转')
logger.debug(LOG, 'redirectToLogin 幂等锁生效,丢弃本次跳转')
return
}
const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : []
const current = pages[pages.length - 1]
if (current && current.route === 'pages/login/login') {
console.log('[auth] redirectToLogin 已在登录页,跳过')
logger.debug(LOG, 'redirectToLogin 已在登录页,跳过')
return
}
console.log('[auth] redirectToLogin 跳转登录页, 当前页=', current && current.route, '栈深=', pages.length)
logger.info(LOG, '跳转登录页, 当前页=', current && current.route, '栈深=', pages.length)
redirecting = true
wx.reLaunch({
url: '/pages/login/login',
@@ -171,6 +175,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
return new Promise<T>((resolve, reject) => {
// 未登录:直接失败,不发请求,避免无 token 时批量 401 引发重定向风暴
if (needAuth && !auth.isLoggedIn()) {
logger.debug(LOG, '未登录直接 reject,不发请求, url=', url)
reject(new ApiError(NOT_LOGIN_CODE, '未登录'))
return
}
@@ -185,6 +190,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
if (token) finalHeader['Authorization'] = `Bearer ${token}`
}
logger.debug(LOG, '请求发起', method, fullUrl, 'needAuth=', needAuth, 'retried=', retried)
wx.request({
url: fullUrl,
method,
@@ -196,6 +202,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
// 网络层异常:响应体无 code
if (!body || typeof body.code !== 'number') {
logger.error(LOG, '响应体无 code(网络层异常)', method, fullUrl, 'statusCode=', res.statusCode)
if (showError) showToast('网络异常,请稍后重试')
reject(new Error('network error'))
return
@@ -205,6 +212,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
// 成功
if (code === 0) {
logger.debug(LOG, '请求成功', method, fullUrl)
resolve(body.data as T)
return
}
@@ -215,6 +223,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
reject(failAuth(code, body.msg, silentAuth, showError))
return
}
logger.info(LOG, '命中登录失效码,尝试刷新后重试, code=', code, 'url=', fullUrl)
doRefresh().then((ok) => {
if (ok) {
doCall(true)
@@ -229,6 +238,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
// 账号禁用(HTTP 200,需单独处理)
if (code === 21001) {
logger.error(LOG, '账号被禁用,清理登录态, code=', code)
auth.clearTokens()
handleAuthExpired()
if (showError) showToast(ERROR_MESSAGES[21001] || '账号已被禁用')
@@ -237,6 +247,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
}
// 其余业务错误
logger.warn(LOG, '业务错误, code=', code, 'url=', fullUrl, 'msg=', body.msg)
if (showError) {
const msg =
(body.details && body.details[0]) || ERROR_MESSAGES[code] || body.msg || '请求失败'
@@ -245,6 +256,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
reject(new ApiError(code, body.msg || '请求失败', body.details))
},
fail: () => {
logger.error(LOG, 'wx.request 失败(网络层)', method, fullUrl)
if (showError) showToast('网络异常,请检查网络后重试')
reject(new Error('request fail'))
},
@@ -276,6 +288,7 @@ export function uploadFile<T = any>(
return new Promise<T>((resolve, reject) => {
// 未登录:直接失败,不发请求
if (!auth.isLoggedIn()) {
logger.debug(LOG, '未登录直接 reject,不上传, url=', url)
reject(new ApiError(NOT_LOGIN_CODE, '未登录'))
return
}
@@ -285,6 +298,7 @@ export function uploadFile<T = any>(
const token = auth.getAccessToken()
if (token) header['Authorization'] = `Bearer ${token}`
logger.debug(LOG, '上传发起, url=', url, 'retried=', retried)
wx.uploadFile({
url: url.startsWith('http') ? url : `${BASE_URL}${API_PREFIX}${url}`,
filePath,
@@ -300,12 +314,14 @@ export function uploadFile<T = any>(
}
if (!body || typeof body.code !== 'number') {
logger.error(LOG, '上传响应解析失败(非 JSON)', url, 'raw=', res.data)
if (showError) showToast('上传失败,请稍后重试')
reject(new Error('upload fail'))
return
}
if (body.code === 0) {
logger.info(LOG, '上传成功, url=', url)
resolve(body.data as T)
return
}
@@ -316,6 +332,7 @@ export function uploadFile<T = any>(
reject(failAuth(body.code, body.msg, silentAuth, showError))
return
}
logger.info(LOG, '上传命中登录失效码,尝试刷新后重试, code=', body.code)
doRefresh().then((ok) => {
if (ok) {
doUpload(true)
@@ -326,12 +343,14 @@ export function uploadFile<T = any>(
return
}
logger.warn(LOG, '上传业务错误, code=', body.code, 'url=', url, 'msg=', body.msg)
const msg =
(body.details && body.details[0]) || ERROR_MESSAGES[body.code] || body.msg || '上传失败'
if (showError) showToast(msg)
reject(new ApiError(body.code, body.msg || '上传失败', body.details))
},
fail: () => {
logger.error(LOG, 'wx.uploadFile 失败(网络层), url=', url)
if (showError) showToast('上传失败,请检查网络后重试')
reject(new Error('upload fail'))
},