From df5492a48a03d3dcf7a37e75b9243e15a6e8238b Mon Sep 17 00:00:00 2001 From: zhengchiliu <857493511@qq.com> Date: Sun, 13 Sep 2026 02:02:51 +0800 Subject: [PATCH] add:log --- .../closet-share-detail.ts | 16 ++++- miniprogram/pages/login/login.ts | 67 ++++++++++++++++--- miniprogram/utils/auth.ts | 17 +---- miniprogram/utils/request.ts | 35 ++++++---- 4 files changed, 98 insertions(+), 37 deletions(-) diff --git a/miniprogram/pages/closet-share-detail/closet-share-detail.ts b/miniprogram/pages/closet-share-detail/closet-share-detail.ts index 5dc05e9..04f0de0 100644 --- a/miniprogram/pages/closet-share-detail/closet-share-detail.ts +++ b/miniprogram/pages/closet-share-detail/closet-share-detail.ts @@ -114,9 +114,21 @@ Page({ onGoLogin() { const redirect = `/pages/closet-share-detail/closet-share-detail?uuid=${this.data.uuid}` + const loginUrl = `/pages/login/login?redirect=${encodeURIComponent(redirect)}` wx.navigateTo({ - url: `/pages/login/login?redirect=${encodeURIComponent(redirect)}`, - fail: () => wx.switchTab({ url: '/pages/profile/profile' }), + url: loginUrl, + fail: (e) => { + // 页面栈满(10 层)时 navigateTo 失败:改用 redirectTo 仍跳登录页, + // 且保留 redirect 参数(原先跳 profile 会丢失来源,登录后回不到分享页) + console.log('[share-detail] navigateTo 登录页失败,改用 redirectTo, err=', e && e.errMsg) + wx.redirectTo({ + url: loginUrl, + fail: (e2) => { + console.log('[share-detail] redirectTo 登录页也失败, err=', e2 && e2.errMsg) + wx.switchTab({ url: '/pages/profile/profile' }) + }, + }) + }, }) }, diff --git a/miniprogram/pages/login/login.ts b/miniprogram/pages/login/login.ts index f9994b5..06e997e 100644 --- a/miniprogram/pages/login/login.ts +++ b/miniprogram/pages/login/login.ts @@ -20,6 +20,7 @@ Page({ }, onLoad(query: Record) { + console.log('[login] onLoad, query=', JSON.stringify(query), 'isLoggedIn=', auth.isLoggedIn()) if (query.redirect) this.setData({ redirect: query.redirect }) if (auth.isLoggedIn()) { this.goAfterLogin() @@ -29,27 +30,50 @@ Page({ // 登录完成后的落地页:带 redirect 时回跳来源页(分享详情等),否则进衣橱 goAfterLogin(fallback = false) { const redirect = this.data.redirect + console.log('[login] goAfterLogin, redirect=', redirect, 'fallback=', fallback) if (redirect && !fallback) { wx.redirectTo({ url: redirect, - fail: () => this.goAfterLogin(true), + fail: (e) => { + console.log('[login] redirect 失败,回退衣橱, err=', e && e.errMsg) + this.goAfterLogin(true) + }, }) return } - wx.switchTab({ url: '/pages/wardrobe/wardrobe' }) + wx.switchTab({ + url: '/pages/wardrobe/wardrobe', + fail: (e) => console.log('[login] switchTab 衣橱失败, err=', e && e.errMsg), + }) }, onLogin() { - if (this.data.loading) return + if (this.data.loading) { + console.log('[login] 登录中,忽略重复点击') + return + } + console.log('[login] 点击登录, redirect=', this.data.redirect) this.setData({ loading: true }) + // 超时兜底:wx.login / wx.request 异常挂起时复位按钮,避免永久 loading 点不动 + this.clearLoginTimer() + ;(this as any).loginTimer = setTimeout(() => { + ;(this as any).loginTimer = null + if (!this.data.loading) return + console.log('[login] 登录超时(30s),复位按钮') + this.setData({ loading: false }) + wx.showToast({ title: '登录超时,请重试', icon: 'none' }) + }, 30000) + wx.login({ success: (res) => { if (!res.code) { - this.setData({ loading: false }) + console.log('[login] wx.login 返回空 code') + this.finishLogin() wx.showToast({ title: '登录失败,请重试', icon: 'none' }) return } + console.log('[login] wx.login 成功, codeLen=', res.code.length) request({ url: '/user/wxlogin', method: 'POST', @@ -57,6 +81,12 @@ Page({ auth: false, }) .then((data) => { + console.log( + '[login] wxlogin 成功, isNew=', + data.user_info && data.user_info.is_new_user, + 'expireTime=', + data.expire_time, + ) auth.setTokens({ accessToken: data.access_token, refreshToken: data.refresh_token, @@ -74,19 +104,40 @@ Page({ this.goAfterLogin() } }) - .catch(() => {}) + .catch((e) => { + console.log('[login] wxlogin 失败, code=', e && e.code, 'msg=', e && e.message) + }) .then(() => { // 无论成功还是失败都复位:分支走向礼包/生日引导时若不复位,登录按钮会永久点不动 - this.setData({ loading: false }) + this.finishLogin() }) }, - fail: () => { - this.setData({ loading: false }) + fail: (e) => { + console.log('[login] wx.login 失败, errMsg=', e && e.errMsg) + this.finishLogin() wx.showToast({ title: '登录失败,请重试', icon: 'none' }) }, }) }, + // 复位登录态:清超时定时器 + 复位按钮 + finishLogin() { + this.clearLoginTimer() + this.setData({ loading: false }) + }, + + clearLoginTimer() { + const timer = (this as any).loginTimer + if (timer) { + clearTimeout(timer) + ;(this as any).loginTimer = null + } + }, + + onUnload() { + this.clearLoginTimer() + }, + showWelcomeGift(userInfo: UserInfo) { // 额度只用于礼包展示:失败静默降级,绝不能触发登出/清 token request<{ quotas: QuotaItem[] }>({ url: '/quota/info', showError: false, silentAuth: true }) diff --git a/miniprogram/utils/auth.ts b/miniprogram/utils/auth.ts index c2cedb0..76cd54c 100644 --- a/miniprogram/utils/auth.ts +++ b/miniprogram/utils/auth.ts @@ -34,21 +34,8 @@ export function isLoggedIn(): boolean { return !!getAccessToken() } -// token 过期提前量(秒):提前 30s 视为过期,避免请求在途时刚好失效 -const EXPIRE_LEAD_SECONDS = 30 - -/** - * access token 是否已过期(仅用于请求前预刷新,不参与登录态判定) - * expire_time 单位兼容秒与毫秒:数值大于 1e12 视为毫秒时间戳。 - */ -export function isTokenExpired(): boolean { - const expireTime = getExpireTime() - if (!expireTime) return false // 未记录过期时间时不臆测,交给后端判定 - - const isMillisecond = expireTime > 1e12 - const expireMs = isMillisecond ? expireTime : expireTime * 1000 - return Date.now() + EXPIRE_LEAD_SECONDS * 1000 >= expireMs -} +// token 过期判定统一由后端 401 驱动,前端不再猜测 expire_time 的单位 +// (秒 / 毫秒 / 剩余秒数无法可靠区分,误判会导致不必要的刷新与误踢登录) export function clearUserInfo(): void { wx.removeStorageSync(STORAGE_KEYS.USER_INFO) diff --git a/miniprogram/utils/request.ts b/miniprogram/utils/request.ts index 76e7d5e..4ab461c 100644 --- a/miniprogram/utils/request.ts +++ b/miniprogram/utils/request.ts @@ -44,9 +44,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) auth.clearTokens() handleAuthExpired() if (showError) showToast('登录已过期,请重新登录') + } else { + console.log('[auth] failAuth 静默失败(不动登录态), code=', code) } return new ApiError(code, msg || '登录已过期') } @@ -66,9 +69,11 @@ function doRefresh(): Promise { const refreshToken = auth.getRefreshToken() const accessToken = auth.getAccessToken() if (!refreshToken || !accessToken) { + console.log('[auth] doRefresh 无 token,放弃刷新') resolve(false) return } + console.log('[auth] doRefresh 发起刷新') wx.request({ url: `${BASE_URL}${API_PREFIX}/user/refresh-token`, method: 'POST', @@ -83,12 +88,17 @@ function doRefresh(): Promise { refreshToken: body.data.refresh_token, expireTime: body.data.expire_time, }) + console.log('[auth] doRefresh 成功') resolve(true) } else { + console.log('[auth] doRefresh 响应异常, code=', body && body.code) resolve(false) } }, - fail: () => resolve(false), + fail: () => { + console.log('[auth] doRefresh 网络失败') + resolve(false) + }, }) }).finally(() => { refreshingPromise = null @@ -116,11 +126,18 @@ let redirecting = false * 2. 当前已在登录页时不重复跳转。 */ export function redirectToLogin(): void { - if (redirecting) return + if (redirecting) { + console.log('[auth] redirectToLogin 幂等锁生效,丢弃本次跳转') + return + } const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [] const current = pages[pages.length - 1] - if (current && current.route === 'pages/login/login') return + if (current && current.route === 'pages/login/login') { + console.log('[auth] redirectToLogin 已在登录页,跳过') + return + } + console.log('[auth] redirectToLogin 跳转登录页, 当前页=', current && current.route, '栈深=', pages.length) redirecting = true wx.reLaunch({ url: '/pages/login/login', @@ -234,15 +251,9 @@ export function request(options: RequestOptions): Promise { }) } - // token 已过期:先静默刷新再发请求,省掉一次必然失败的 401 往返 - // (刷新失败也不直接拒绝:仍发一次,由后端判定,避免网络抖动就把用户踢下线) - if (needAuth && auth.isTokenExpired()) { - doRefresh().then(() => { - doCall() - }) - return - } - + // 直接发请求:由后端 401 判定 token 是否失效,再触发 doRefresh 重试。 + // 不再做前端「过期预刷新」:expire_time 单位(秒/毫秒/剩余秒数)无法可靠猜测, + // 误判会让每次请求都多一次刷新往返,刷新偶发失败时把已登录用户踢回登录页。 doCall() }) }