Basic_Mini 项目初始化
· Basic_Mini
今日进展
- 六层架构搭建:页面 → 组件 → 服务 → 接口 → 基础设施 → 模型,与 Basic_Web 五层架构一一对应
- JWT 双 Token 自动刷新:Access 过期自动用 Refresh 换新,刷新期间其他请求排队等待
- Token 加密存储:AES 加密后存入 wx.storage,防止反编译泄露
- 路由守卫:需登录页面自动跳转登录,需权限页面自动检查权限码
- 权限组件:auth-guard(登录检查)、permission-guard(权限检查)
- 统一错误处理:401 自动刷新 Token、403 提示权限不足、429 提示限流、5xx 提示服务器异常
- 基础组件:nav-bar(导航栏)、empty-state(空状态)、loading-state(加载状态)
- 页面骨架:登录、注册、忘记密码、首页、个人中心、修改密码
关键代码/伪代码
Token 自动刷新 — 请求排队
// Token 刷新最头疼的问题:
// 同时发了5个请求,Access Token 都过期了
// 如果5个请求都去刷新,会触发5次刷新,后面的可能失败
// 解决方案:只刷新一次,其他请求排队等待
CLASS HttpClient:
refreshTokenPromise: Promise | null = null
ASYNC request(url, options):
TRY:
RETURN AWAIT this.rawRequest(url, options)
CATCH (error):
IF error.code === 401 AND this.hasRefreshToken():
// 第一个发现过期的请求负责刷新
IF NOT this.refreshTokenPromise:
this.refreshTokenPromise = this.refreshTokens()
// 其他请求排队等待同一个刷新 Promise
AWAIT this.refreshTokenPromise
this.refreshTokenPromise = null
// 刷新成功,重试原请求
RETURN AWAIT this.rawRequest(url, options)
// 刷新也失败了,清空认证数据,跳转登录
this.clearAuth()
router.navigateTo('/pages/auth/login/login')
THROW error
路由守卫 — 自动检查登录和权限
// 路由守卫:跳转前自动检查登录状态和权限
// 不用每个页面都写 if (!isLoggedIn) { ... }
CLASS Router:
ASYNC navigateTo(url: string):
// 检查目标页面是否需要登录
IF requiresAuth(url):
IF NOT authService.isLoggedIn():
// 保存目标路径,登录后自动跳回
storage.set('redirect_url', url)
RETURN wx.navigateTo({ url: '/pages/auth/login/login' })
// 检查目标页面是否需要特定权限
requiredPerm = getRequiredPermission(url)
IF requiredPerm AND NOT permissionService.hasPermission(requiredPerm):
wx.showToast({ title: '权限不足', icon: 'none' })
RETURN
// 通过所有检查,正常跳转
wx.navigateTo({ url })
分层架构 — 页面不直接调用 API
// 错误写法:页面直接调 API
// Page({
// async onLoad() {
// const res = await client.get('/api/v1/users/me') // 禁止!
// }
// })
// 正确写法:页面调 Service,Service 调 API
// services/auth-service.ts
CLASS AuthService:
ASYNC login(data: LoginRequest): Promise:
logger.info('auth_login_start', { username: data.username })
TRY:
tokenPair = AWAIT auth.login(data) // API 层
this.saveTokens(tokenPair)
profile = AWAIT this.loadProfile()
logger.info('auth_login_success', { user_id: profile.id })
RETURN profile
CATCH (e):
logger.error('auth_login_failed', { error: String(e) })
THROW e
// pages/auth/login/login.ts
Page({
ASYNC onLogin():
this.setData({ loading: true })
TRY:
AWAIT authService.login({ username, password })
wx.showToast({ title: '登录成功', icon: 'success' })
CATCH (e):
wx.showToast({ title: e.message, icon: 'none' })
FINALLY:
this.setData({ loading: false })
})
遇到的问题
- 微信小程序没有 npm 原生支持:需要先 npm install 再"构建 npm",而且构建后的路径和 node_modules 不同。解决方案:package.json 放在 src/ 目录下,构建后 miniprogram_npm 自动可用
- TypeScript 严格模式下 Page/Component 的类型推断不友好:微信官方没有提供完整的类型定义。解决方案:自己定义 PageOptions 和 ComponentOptions 接口
- Token 加密存储的密钥管理:密钥不能硬编码在代码里(反编译可读),也不能每次随机生成(换设备就解不开)。解决方案:密钥由设备指纹 + 应用密钥派生
明日计划
- 完善权限组件的 UI 反馈:无权限时显示空状态而非空白
- 添加分包页面示例
- 与 Basic_Web 联调登录流程