feat: 优化
This commit is contained in:
@@ -24,8 +24,7 @@ const WHITE_LIST = [
|
|||||||
* 检查 URL 是否在白名单中
|
* 检查 URL 是否在白名单中
|
||||||
*/
|
*/
|
||||||
function isInWhiteList(url) {
|
function isInWhiteList(url) {
|
||||||
if (!url) return false
|
return !!(url && WHITE_LIST.some(path => url.includes(path)))
|
||||||
return WHITE_LIST.some((path) => url.includes(path))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,23 +58,34 @@ function onRefreshed() {
|
|||||||
* 注意:只做清理工作,不处理重定向(重定向由上层回调处理)
|
* 注意:只做清理工作,不处理重定向(重定向由上层回调处理)
|
||||||
*/
|
*/
|
||||||
let isHandling401 = false
|
let isHandling401 = false
|
||||||
|
let handling401Timeout = null
|
||||||
|
|
||||||
function handle401Error(error) {
|
function handle401Error(error) {
|
||||||
if (isHandling401) return
|
// 防止重复处理
|
||||||
|
if (isHandling401 || error?._handled) {
|
||||||
isHandling401 = true
|
return
|
||||||
|
|
||||||
try {
|
|
||||||
// 清空token
|
|
||||||
tokenManager.clearTokens()
|
|
||||||
console.warn('Token已清空,因401错误')
|
|
||||||
} catch (e) {
|
|
||||||
console.error('清空 token 失败:', e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 延迟重置标志
|
isHandling401 = true
|
||||||
setTimeout(() => {
|
error && (error._handled = true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
tokenManager.clearTokens()
|
||||||
|
const message = error?.needRelogin
|
||||||
|
? '[HTTP] Token已清空,refreshToken无效需要重新登录'
|
||||||
|
: '[HTTP] Token已清空,因401错误'
|
||||||
|
console.warn(message)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[HTTP] 清空 token 失败:', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handling401Timeout) {
|
||||||
|
clearTimeout(handling401Timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
handling401Timeout = setTimeout(() => {
|
||||||
isHandling401 = false
|
isHandling401 = false
|
||||||
}, 2000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,66 +127,71 @@ export function createClientAxios(options = {}) {
|
|||||||
// 检查是否需要认证
|
// 检查是否需要认证
|
||||||
const needToken = config.headers?.isToken !== false && !isInWhiteList(config.url || '')
|
const needToken = config.headers?.isToken !== false && !isInWhiteList(config.url || '')
|
||||||
|
|
||||||
if (needToken) {
|
if (!needToken) {
|
||||||
// 检查 token 是否即将过期(30秒缓冲)
|
return config
|
||||||
const BUFFER_TIME = 30 * 1000
|
}
|
||||||
const currentToken = tokenManager.getAccessToken()
|
|
||||||
|
|
||||||
if (!currentToken) {
|
// 检查 token 是否即将过期(30秒缓冲)
|
||||||
console.warn('[Token] 没有可用的 accessToken')
|
const BUFFER_TIME = 30 * 1000
|
||||||
|
const currentToken = tokenManager.getAccessToken()
|
||||||
|
|
||||||
|
if (!currentToken) {
|
||||||
|
console.warn('[Token] 没有可用的 accessToken')
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTokenExpired = tokenManager.isExpired(BUFFER_TIME)
|
||||||
|
|
||||||
|
if (!isTokenExpired) {
|
||||||
|
// Token 未过期,直接添加 Authorization 头
|
||||||
|
const authHeader = tokenManager.getAuthHeader()
|
||||||
|
if (authHeader) {
|
||||||
|
config.headers.Authorization = authHeader
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token 即将过期,需要刷新
|
||||||
|
console.info('[Token] Token刷新')
|
||||||
|
|
||||||
|
// 如果不在刷新过程中,启动刷新
|
||||||
|
if (!isRefreshing) {
|
||||||
|
isRefreshing = true
|
||||||
|
|
||||||
|
if (!refreshTokenFn || typeof refreshTokenFn !== 'function') {
|
||||||
|
console.warn('[Token] 未提供刷新函数,跳过刷新')
|
||||||
|
isRefreshing = false
|
||||||
|
onRefreshed()
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTokenExpired = tokenManager.isExpired(BUFFER_TIME)
|
refreshTokenFn()
|
||||||
|
.then(() => {
|
||||||
if (isTokenExpired) {
|
console.info('[Token] 刷新成功')
|
||||||
console.info('[Token] Token刷新')
|
isRefreshing = false
|
||||||
|
onRefreshed()
|
||||||
// 如果不在刷新过程中,启动刷新
|
|
||||||
if (!isRefreshing) {
|
|
||||||
isRefreshing = true
|
|
||||||
|
|
||||||
// 执行刷新(使用上层传入的刷新函数)
|
|
||||||
if (refreshTokenFn && typeof refreshTokenFn === 'function') {
|
|
||||||
refreshTokenFn()
|
|
||||||
.then(() => {
|
|
||||||
console.info('[Token] 刷新成功')
|
|
||||||
isRefreshing = false
|
|
||||||
onRefreshed()
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
isRefreshing = false
|
|
||||||
onRefreshed()
|
|
||||||
console.error('[Token] 刷新失败:', error.message)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
console.warn('[Token] 未提供刷新函数,跳过刷新')
|
|
||||||
isRefreshing = false
|
|
||||||
onRefreshed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待刷新完成
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
subscribeTokenRefresh(() => {
|
|
||||||
// 刷新完成后,重新获取 token 并添加到请求头
|
|
||||||
const authHeader = tokenManager.getAuthHeader()
|
|
||||||
if (authHeader) {
|
|
||||||
config.headers.Authorization = authHeader
|
|
||||||
}
|
|
||||||
resolve(config)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} else {
|
.catch((error) => {
|
||||||
// Token 未过期,直接添加 Authorization 头
|
isRefreshing = false
|
||||||
|
onRefreshed()
|
||||||
|
console.error('[Token] 刷新失败:', error.message)
|
||||||
|
|
||||||
|
if (error.code === 401 && error.needRelogin) {
|
||||||
|
console.info('[Token] refreshToken无效,需要重新登录')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待刷新完成
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
subscribeTokenRefresh(() => {
|
||||||
const authHeader = tokenManager.getAuthHeader()
|
const authHeader = tokenManager.getAuthHeader()
|
||||||
if (authHeader) {
|
if (authHeader) {
|
||||||
config.headers.Authorization = authHeader
|
config.headers.Authorization = authHeader
|
||||||
}
|
}
|
||||||
}
|
resolve(config)
|
||||||
}
|
})
|
||||||
|
})
|
||||||
return config
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
@@ -195,31 +210,24 @@ export function createClientAxios(options = {}) {
|
|||||||
error.code = data?.code
|
error.code = data?.code
|
||||||
error.data = data
|
error.data = data
|
||||||
|
|
||||||
// 业务码 401/403 只在响应拦截器处理,避免重复处理
|
// 业务码 403 只在响应拦截器处理,避免重复处理
|
||||||
if (data.code === 401 && typeof on401 === 'function') {
|
|
||||||
on401(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.code === 403 && typeof on403 === 'function') {
|
if (data.code === 403 && typeof on403 === 'function') {
|
||||||
// 使用通用的权限不足错误,不使用后端返回的 message
|
|
||||||
const forbiddenError = new Error('权限不足,无法访问该资源')
|
const forbiddenError = new Error('权限不足,无法访问该资源')
|
||||||
forbiddenError.code = 403
|
forbiddenError.code = 403
|
||||||
on403(forbiddenError)
|
on403(forbiddenError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 抛出错误,业务代码可以捕获
|
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// HTTP 状态码 401/403 只在错误拦截器处理
|
const status = error.response?.status
|
||||||
if (error.response?.status === 401 && typeof on401 === 'function') {
|
|
||||||
on401(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.response?.status === 403 && typeof on403 === 'function') {
|
if (status === 401 && typeof on401 === 'function') {
|
||||||
|
on401(error)
|
||||||
|
} else if (status === 403 && typeof on403 === 'function') {
|
||||||
const forbiddenError = new Error('权限不足,无法访问该资源')
|
const forbiddenError = new Error('权限不足,无法访问该资源')
|
||||||
forbiddenError.code = 403
|
forbiddenError.code = 403
|
||||||
on403(forbiddenError)
|
on403(forbiddenError)
|
||||||
|
|||||||
@@ -12,26 +12,29 @@ const SERVER_BASE = API_BASE.APP_MEMBER
|
|||||||
* @param {Object} info - 包含 accessToken 和 refreshToken 的对象
|
* @param {Object} info - 包含 accessToken 和 refreshToken 的对象
|
||||||
*/
|
*/
|
||||||
function saveTokens(info) {
|
function saveTokens(info) {
|
||||||
if (info?.accessToken || info?.refreshToken) {
|
if (!info?.accessToken && !info?.refreshToken) {
|
||||||
tokenManager.setTokens({
|
return
|
||||||
accessToken: info.accessToken || '',
|
|
||||||
refreshToken: info.refreshToken || '',
|
|
||||||
expiresTime: info.expiresTime || 0, // 直接传递,由 token-manager 处理格式转换
|
|
||||||
tokenType: info.tokenType || 'Bearer'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
tokenManager.setTokens({
|
||||||
|
accessToken: info.accessToken || '',
|
||||||
|
refreshToken: info.refreshToken || '',
|
||||||
|
expiresTime: info.expiresTime || 0,
|
||||||
|
tokenType: info.tokenType || 'Bearer'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应拦截(可选):统一错误处理
|
* 清除用户信息缓存
|
||||||
*/
|
*/
|
||||||
// api.interceptors.response.use(
|
async function clearUserCache() {
|
||||||
// (resp) => resp,
|
try {
|
||||||
// (err) => {
|
const { clearUserInfoCache } = await import('@gold/hooks/web/useUserInfo')
|
||||||
// // 统一错误日志/提示
|
clearUserInfoCache()
|
||||||
// return Promise.reject(err);
|
} catch (e) {
|
||||||
// }
|
// 清除缓存失败不影响登录流程
|
||||||
// );
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信场景枚举(请与后端配置保持一致)
|
* 短信场景枚举(请与后端配置保持一致)
|
||||||
@@ -50,8 +53,8 @@ export const SMS_SCENE = {
|
|||||||
* 短信模板编码常量
|
* 短信模板编码常量
|
||||||
*/
|
*/
|
||||||
export const SMS_TEMPLATE_CODE = {
|
export const SMS_TEMPLATE_CODE = {
|
||||||
USER_REGISTER: 'muye-user-code', // 用户注册模板编码
|
USER_REGISTER: 'muye-user-code',
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号密码登录
|
* 账号密码登录
|
||||||
@@ -62,19 +65,11 @@ export const SMS_TEMPLATE_CODE = {
|
|||||||
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
|
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
|
||||||
*/
|
*/
|
||||||
export async function loginByPassword(mobile, password) {
|
export async function loginByPassword(mobile, password) {
|
||||||
const { data } = await api.post(`${SERVER_BASE}/auth/login`, { mobile, password });
|
const { data } = await api.post(`${SERVER_BASE}/auth/login`, { mobile, password })
|
||||||
const info = data || {};
|
const info = data || {}
|
||||||
saveTokens(info);
|
saveTokens(info)
|
||||||
|
await clearUserCache()
|
||||||
// 清除用户信息缓存,确保登录后获取最新信息
|
return info
|
||||||
try {
|
|
||||||
const { clearUserInfoCache } = await import('@gold/hooks/web/useUserInfo')
|
|
||||||
clearUserInfoCache()
|
|
||||||
} catch (e) {
|
|
||||||
// 清除缓存失败不影响登录流程
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,11 +82,12 @@ export async function loginByPassword(mobile, password) {
|
|||||||
* @returns {Promise<Object>} 后端通用响应结构
|
* @returns {Promise<Object>} 后端通用响应结构
|
||||||
*/
|
*/
|
||||||
export async function sendSmsCode(mobile, scene, templateCode) {
|
export async function sendSmsCode(mobile, scene, templateCode) {
|
||||||
const body = { scene };
|
const body = { scene }
|
||||||
if (mobile) body.mobile = mobile; // 修改密码场景后端会根据当前登录用户自动填充手机号
|
if (mobile) body.mobile = mobile
|
||||||
if (templateCode) body.templateCode = templateCode; // 添加模板编码参数
|
if (templateCode) body.templateCode = templateCode
|
||||||
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, body);
|
|
||||||
return data;
|
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, body)
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,8 +100,8 @@ export async function sendSmsCode(mobile, scene, templateCode) {
|
|||||||
* @returns {Promise<Object>} 后端通用响应结构
|
* @returns {Promise<Object>} 后端通用响应结构
|
||||||
*/
|
*/
|
||||||
export async function validateSmsCode(mobile, code, scene) {
|
export async function validateSmsCode(mobile, code, scene) {
|
||||||
const { data } = await api.post(`${SERVER_BASE}/auth/validate-sms-code`, { mobile, code, scene });
|
const { data } = await api.post(`${SERVER_BASE}/auth/validate-sms-code`, { mobile, code, scene })
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,19 +113,11 @@ export async function validateSmsCode(mobile, code, scene) {
|
|||||||
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
|
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
|
||||||
*/
|
*/
|
||||||
export async function loginBySms(mobile, code) {
|
export async function loginBySms(mobile, code) {
|
||||||
const { data } = await api.post(`${SERVER_BASE}/auth/sms-login`, { mobile, code });
|
const { data } = await api.post(`${SERVER_BASE}/auth/sms-login`, { mobile, code })
|
||||||
const info = data || {};
|
const info = data || {}
|
||||||
saveTokens(info);
|
saveTokens(info)
|
||||||
|
await clearUserCache()
|
||||||
// 清除用户信息缓存,确保登录后获取最新信息
|
return info
|
||||||
try {
|
|
||||||
const { clearUserInfoCache } = await import('@gold/hooks/web/useUserInfo')
|
|
||||||
clearUserInfoCache()
|
|
||||||
} catch (e) {
|
|
||||||
// 清除缓存失败不影响登录流程
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,26 +127,36 @@ export async function loginBySms(mobile, code) {
|
|||||||
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
|
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
|
||||||
*/
|
*/
|
||||||
export async function refreshToken() {
|
export async function refreshToken() {
|
||||||
const rt = tokenManager.getRefreshToken();
|
const rt = tokenManager.getRefreshToken()
|
||||||
if (!rt) throw new Error('缺少 refresh_token');
|
if (!rt) throw new Error('缺少 refresh_token')
|
||||||
// refreshToken 作为 URL 查询参数传递
|
|
||||||
const { data } = await api.post(`${SERVER_BASE}/auth/refresh-token`, null, { params: { refreshToken: rt } });
|
|
||||||
const info = data || {};
|
|
||||||
saveTokens(info);
|
|
||||||
|
|
||||||
// 清除用户信息缓存,因为 token 刷新后用户信息可能已更新
|
const { data } = await api.post(`${SERVER_BASE}/auth/refresh-token`, null, { params: { refreshToken: rt } })
|
||||||
try {
|
|
||||||
const { clearUserInfoCache } = await import('@gold/hooks/web/useUserInfo')
|
// 检查业务状态码
|
||||||
clearUserInfoCache()
|
if (data?.code === 401) {
|
||||||
} catch (e) {
|
// 401: refreshToken 无效或过期
|
||||||
// 清除缓存失败不影响登录流程
|
tokenManager.clearTokens()
|
||||||
|
await clearUserCache()
|
||||||
|
router.push('/login')
|
||||||
|
|
||||||
|
const authError = new Error('登录已过期,请重新登录')
|
||||||
|
authError.code = 401
|
||||||
|
authError.needRelogin = true
|
||||||
|
throw authError
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
if (data?.code !== 0 && data?.code !== 200) {
|
||||||
|
throw new Error(data?.message || data?.msg || '刷新token失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
const info = data || {}
|
||||||
|
saveTokens(info)
|
||||||
|
await clearUserCache()
|
||||||
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录态下:发送“修改密码”验证码
|
* 登录态下:发送"修改密码"验证码
|
||||||
* - 场景:SMS_SCENE.MEMBER_UPDATE_PASSWORD
|
* - 场景:SMS_SCENE.MEMBER_UPDATE_PASSWORD
|
||||||
* - 特性:后端会以当前登录用户的手机号为准,无需传 mobile
|
* - 特性:后端会以当前登录用户的手机号为准,无需传 mobile
|
||||||
* POST /member/auth/send-sms-code
|
* POST /member/auth/send-sms-code
|
||||||
@@ -168,8 +166,8 @@ export async function refreshToken() {
|
|||||||
export async function sendUpdatePasswordCode() {
|
export async function sendUpdatePasswordCode() {
|
||||||
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, {
|
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, {
|
||||||
scene: SMS_SCENE.MEMBER_UPDATE_PASSWORD,
|
scene: SMS_SCENE.MEMBER_UPDATE_PASSWORD,
|
||||||
});
|
})
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -184,12 +182,12 @@ export async function updatePasswordBySmsCode(newPassword, smsCode) {
|
|||||||
const { data } = await api.put(`${SERVER_BASE}/user/update-password`, {
|
const { data } = await api.put(`${SERVER_BASE}/user/update-password`, {
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
code: smsCode,
|
code: smsCode,
|
||||||
});
|
})
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 未登录:发送“忘记密码”验证码
|
* 未登录:发送"忘记密码"验证码
|
||||||
* - 场景:SMS_SCENE.MEMBER_RESET_PASSWORD
|
* - 场景:SMS_SCENE.MEMBER_RESET_PASSWORD
|
||||||
* POST /member/auth/send-sms-code
|
* POST /member/auth/send-sms-code
|
||||||
*
|
*
|
||||||
@@ -200,8 +198,8 @@ export async function sendResetPasswordCode(mobile) {
|
|||||||
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, {
|
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, {
|
||||||
mobile,
|
mobile,
|
||||||
scene: SMS_SCENE.MEMBER_RESET_PASSWORD,
|
scene: SMS_SCENE.MEMBER_RESET_PASSWORD,
|
||||||
});
|
})
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -218,8 +216,8 @@ export async function resetPasswordBySms(mobile, newPassword, smsCode) {
|
|||||||
mobile,
|
mobile,
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
code: smsCode,
|
code: smsCode,
|
||||||
});
|
})
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -234,11 +232,11 @@ export async function getUserInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* “手机+验证码+密码注册”组合流程(基于短信登录即注册 + 设置密码)
|
* "手机+验证码+密码注册"组合流程(基于短信登录即注册 + 设置密码)
|
||||||
* 说明:
|
* 说明:
|
||||||
* - 1) 发送登录场景验证码(可选:若已拿到 code 可跳过)
|
* - 1) 发送登录场景验证码(可选:若已拿到 code 可跳过)
|
||||||
* - 2) 短信登录:首次会自动注册并返回 token
|
* - 2) 短信登录:首次会自动注册并返回 token
|
||||||
* - 3) 登录态下发送“修改密码”验证码
|
* - 3) 登录态下发送"修改密码"验证码
|
||||||
* - 4) 用短信验证码设置密码
|
* - 4) 用短信验证码设置密码
|
||||||
*
|
*
|
||||||
* @param {string} mobile - 手机号(必填)
|
* @param {string} mobile - 手机号(必填)
|
||||||
@@ -248,17 +246,11 @@ export async function getUserInfo() {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export async function registerWithMobileCodePassword(mobile, loginCode, newPassword, updatePwdCode) {
|
export async function registerWithMobileCodePassword(mobile, loginCode, newPassword, updatePwdCode) {
|
||||||
// 1) 可选:发送登录场景验证码(若已拿到 loginCode 可跳过)
|
|
||||||
// await sendSmsCode(mobile, SMS_SCENE.MEMBER_LOGIN);
|
|
||||||
|
|
||||||
// 2) 短信登录(首次即注册)
|
// 2) 短信登录(首次即注册)
|
||||||
await loginBySms(mobile, loginCode);
|
await loginBySms(mobile, loginCode)
|
||||||
|
|
||||||
// 3) 登录态下发送“修改密码”验证码(短信会发到当前账号绑定的手机号)
|
|
||||||
// await sendUpdatePasswordCode();
|
|
||||||
|
|
||||||
// 4) 用短信验证码设置密码
|
// 4) 用短信验证码设置密码
|
||||||
await updatePasswordBySmsCode(newPassword, updatePwdCode);
|
await updatePasswordBySmsCode(newPassword, updatePwdCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,29 +22,16 @@ export function createHttpClient(options = {}) {
|
|||||||
const httpClient = createClientAxios({
|
const httpClient = createClientAxios({
|
||||||
baseURL: '/',
|
baseURL: '/',
|
||||||
timeout: 180000,
|
timeout: 180000,
|
||||||
refreshTokenFn: refreshToken, // 传递刷新函数给拦截器
|
refreshTokenFn: refreshToken,
|
||||||
on401: async (error) => {
|
on401: async (error) => {
|
||||||
// 401:优先使用上层自定义处理
|
|
||||||
if (on401) {
|
if (on401) {
|
||||||
await on401(error)
|
await on401(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
router.push('/login')
|
||||||
// 默认处理:尝试刷新token
|
|
||||||
try {
|
|
||||||
await refreshToken()
|
|
||||||
error._handled = true
|
|
||||||
error._tokenRefreshed = true
|
|
||||||
} catch (refreshError) {
|
|
||||||
router.push('/login')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
on403: (error) => {
|
on403: (error) => {
|
||||||
if (on403) {
|
on403 ? on403(error) : router.push('/login')
|
||||||
on403(error)
|
|
||||||
} else {
|
|
||||||
router.push('/login')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -74,38 +61,16 @@ export default http
|
|||||||
*
|
*
|
||||||
* const myHttp = createHttpClient()
|
* const myHttp = createHttpClient()
|
||||||
* myHttp.interceptors.request.use((config) => {
|
* myHttp.interceptors.request.use((config) => {
|
||||||
* // 添加自定义请求头
|
|
||||||
* config.headers['X-Custom-Header'] = 'value'
|
* config.headers['X-Custom-Header'] = 'value'
|
||||||
* return config
|
* return config
|
||||||
* })
|
* })
|
||||||
* await myHttp.post('/api/data')
|
|
||||||
*
|
*
|
||||||
* 3. 自定义 401 处理
|
* 3. 自定义 401 处理
|
||||||
* import { createHttpClient } from '@/api/http'
|
|
||||||
*
|
|
||||||
* const myHttp = createHttpClient({
|
* const myHttp = createHttpClient({
|
||||||
* on401: (error) => {
|
* on401: (error) => {
|
||||||
* // 自定义 401 处理逻辑
|
|
||||||
* console.log('自定义 401 处理')
|
* console.log('自定义 401 处理')
|
||||||
* }
|
* }
|
||||||
* })
|
* })
|
||||||
*
|
|
||||||
* 4. 高级用法:自动刷新 token 并重试请求
|
|
||||||
* import { createHttpClient } from '@/api/http'
|
|
||||||
*
|
|
||||||
* const myHttp = createHttpClient()
|
|
||||||
*
|
|
||||||
* try {
|
|
||||||
* const response = await myHttp.post('/api/data')
|
|
||||||
* console.log(response.data)
|
|
||||||
* } catch (error) {
|
|
||||||
* // 如果是 401 且刷新失败,会自动调用 onAuthFailed 回调
|
|
||||||
* console.error('请求失败:', error.message)
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* 注意:当 401 发生时,系统会自动尝试刷新 token。
|
|
||||||
* 如果刷新成功,会使用相同的 http 实例重新发起请求,
|
|
||||||
* 确保自定义拦截器被正确应用。
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user