ai-c/小程序前端开发与后端API对接经验汇总.md
2026-02-02 18:21:32 +08:00

8.8 KiB
Raw Permalink Blame History

小程序前端开发与后端 API 对接经验汇总

适用范围:本仓库小程序前端(qianduan/qianduan-code/miniprogram)。目标是让新同学能在不踩坑的情况下完成页面开发、样式对齐和后端 API 对接。

1. 项目结构与入口

  • 小程序目录:qianduan/qianduan-code/miniprogram
  • 全局入口:app.js / app.json / app.wxss
  • 页面目录:pages/*
  • 通用能力:
    • 请求封装:utils/api.js
    • 登录态:utils/auth.js
    • 统一错误处理:utils/errorHandler.js
    • 图片 URL 处理:utils/imageUrl.js
  • 环境与常量:config/index.js

2. 环境与 baseURL非常关键

后端 API 的 baseURL 由 config/index.js 管理:

  • ENV.{development,staging,production}.API_BASE_URL
  • CURRENT_ENV
  • REQUEST_TIMEOUT(默认 30s
  • PAGE_SIZE(默认 20
  • STORAGE_KEYStoken/user 等 storage key 的唯一来源)

建议实践:

  • 开发阶段用 development,发版/线上联调切 production
  • 不要在页面里硬编码域名或 /api 前缀,一律走 config.API_BASE_URL

另外,app.js 会把 config.API_BASE_URL 去掉 /api 后写到 globalData.baseUrl 并落地到 storage.baseUrl,主要给 utils_new 那套请求封装使用。正常业务开发推荐统一使用 utils/api.js 这一套,避免 token key 和 baseUrl 来源混乱。

3. 请求封装与 header 格式(统一约定)

3.1 推荐做法:只用 utils/api.js

utils/api.js 内部封装了 request(),完成以下事情:

  • URL 拼接:config.API_BASE_URL + url
  • header 默认包含:
    • Content-Type: application/json
    • Authorization: Bearer <token>token 从 wx.getStorageSync(config.STORAGE_KEYS.TOKEN) 取)
  • 401未登录/登录过期)处理:
    • 非 silent 模式会清理本地登录信息token/user/userId/expiry
    • 同步 app.globalData.isLoggedIn = false
    • 尝试调用当前页 onAuthRequired()(如果页面实现了该方法)
  • silent 模式用于不希望打断用户操作的接口401 时不清本地登录态,只 reject

页面层调用建议:

import api from '../../utils/api'
import { handleApiError } from '../../utils/errorHandler'

Page({
  async onLoad() {
    try {
      wx.showLoading({ title: '加载中' })
      const res = await api.user.getProfile()
      this.setData({ profile: res.data })
    } catch (err) {
      handleApiError(err)
    } finally {
      wx.hideLoading()
    }
  }
})

3.2 不推荐混用:utils_new/request.js

仓库里还有一套 utils_new/request.js(更偏调试/可切 baseUrl但它使用的 token key 是写死的 auth_token,而主体系使用 config.STORAGE_KEYS.TOKEN(同为 auth_token 但请以配置为准)。混用会导致以下问题:

  • 你以为登录了,实际请求没带对 token
  • baseUrl 读取路径不同,导致部分页面请求走了另一个域名/端口

结论:业务开发优先只用 utils/api.js;除非明确是在做本地联调/临时调试,并保证 token/baseUrl 与主体系一致。

4. 登录态与鉴权(页面开发常见坑)

核心逻辑在 utils/auth.jsapp.js

  • app.js 启动会调用 checkLoginStatus()
    • 先本地检查 token
    • 再调用 auth.verifyLogin() 请求服务端 /auth/me 做校验
    • 网络异常时可能允许用本地缓存 userInfo 继续使用(提升弱网体验)
  • 页面若必须登录才能访问,建议用 auth.ensureLogin() 做统一校验,校验失败会跳登录页
  • token/用户信息写入请走 auth.saveUserInfo(user, token, expiresAt)

页面侧最佳实践:

  • 需要登录的页面,在 onLoad/onShow 里先 await auth.ensureLogin() 再拉数据
  • 有接口需要“静默拉取”(比如后台刷新余额),用 api.request(url, { silent: true }) 或 API 方法暴露的 silent 选项(按现有实现为准)
  • 需要 401 时做自定义交互的页面,提供 onAuthRequired() 方法(例如弹窗提示/引导登录),否则默认行为是清理登录态并由页面自行处理后续

5. 统一错误处理(减少页面重复代码)

utils/errorHandler.js 提供了:

  • handleApiError(err):统一 toast/提示文案
  • retryOnError(fn, { maxRetries, retryDelay }):可重试逻辑(认证错误不会重试)

建议实践:

  • 页面 catch 里优先调用 handleApiError(err),不要每个页面自己写一套 toast 文案
  • 对用户关键路径(下单/提现提交):
    • 网络错误提示要明确
    • 禁止无限重试

6. 分页与列表加载(约定优先)

当前工程的分页没有抽象成统一 paginate()更多是“API 方法里给默认分页参数 + 页面侧传参”:

  • 常见参数:page + pageSize(或部分接口用 limit
  • 默认值可参考 config.PAGE_SIZE

建议实践:

  • 页面 data 里维护:page, pageSize, list, loading, hasMore
  • onReachBottom 时判 hasMore && !loading 再请求下一页
  • 后端返回是否还有更多,以返回字段为准(如果没有统一字段,就以 list.length < pageSize 推断)

7. 上传与图片 URL最容易漏 token

7.1 上传

使用 utils/api.jsuploadFile()

  • 上传地址:${config.API_BASE_URL}/upload
  • 携带 Authorization: Bearer <token>
  • 支持 formData.folder 指定目录
  • 兼容多种返回格式({code:0}{success:true}

7.2 图片 URL 拼接

后端返回相对路径时,用 utils/imageUrl.jsgetFullImageUrl() 拼成完整地址(基于 API_BASE_URL 去掉 /api)。

8. 头部与页面结构(统一样式框架)

工程里常见的头部结构是“固定导航 + 状态栏占位 + 标题 + 返回按钮”:

  • 导航容器:nav-container
  • 状态栏占位:status-bar
  • 导航栏:nav-bar
  • 返回按钮:nav-back
  • 标题:nav-title

常见页面结构示例可参考:

  • 提现页:pages/withdraw/withdraw.wxmlpages/withdraw/withdraw.wxss
  • 充值页:pages/recharge/recharge.wxml
  • 提现记录:pages/withdraw-records/withdraw-records.wxml

建议实践:

  • 导航容器固定fixed内容区通过 padding-top: {{totalNavHeight}}pxpadding-top: {{totalNavHeight + n}}px 避免被遮挡
  • 页面根节点常用:<view class="page safe-bottom">,保证底部安全区

9. 整体样式风格(如何保持一致)

9.1 全局设计令牌Design Tokens

app.wxss 定义了全局 CSS 变量(建议优先使用):

  • --primary--primary-light
  • --foreground--muted--border
  • --radius

并补齐了全局基础类:

  • .btn-reset:用于 button去掉默认边框与默认点击态差异
  • .safe-bottom:适配底部安全区

9.2 页面级常用视觉语言

在本项目里,“一致感”主要来自以下元素:

  • 背景:浅紫/粉色系渐变或纯色(如 #E8C3D4linear-gradient(180deg, #F8F5FF 0%, #FFFFFF 100%)
  • 卡片:白底 + 大圆角20rpx~48rpx+ 轻阴影 + 适度边框
  • 主按钮:紫色渐变(#B06AB3 → #9B4D9E+ 胶囊圆角999rpx+ 统一阴影
  • 文案层级标题更粗更深700~900说明文字更浅#6B7280/#9CA3AF

建议做法:

  • 新页面先找一个“风格相近”的现有页面抄结构与基础样式,再替换业务内容
  • 少做随意的颜色与圆角,优先复用现有渐变、阴影、字号层级

10. 交互与组件(避免嵌套交互坑)

约定:交互元素不要互相嵌套(例如可点击容器里再放 button 或另一个可点击 view。如果需要整块可点

  • 要么外层用 bindtap,内部不用 button用普通 view/text 模拟按钮)
  • 要么使用 button 做唯一点击源,外层不再绑事件

这类嵌套会在检查工具/规范中触发警告,也容易造成点击穿透/事件冒泡问题。

11. 新增/修改 API 的推荐流程

  1. utils/api.js 增加/修改对应模块方法(保持命名与路径一致)
  2. 请求一律通过内部 request()(确保 header、401、timeout、错误格式一致
  3. 页面侧只调用 api.xxx.yyy(),不直接拼 URL、不直接 wx.request
  4. 异常统一走 handleApiError,少在页面写自定义错误文案

12. 排查清单(定位问题最快)

  • 请求没到后端:
    • config.CURRENT_ENV 是否正确
    • config.API_BASE_URL 是否正确(是否带了 /api
    • 是否混用了 utils_new 导致 baseUrl/token 读取来源不一致
  • 401/未登录:
    • storage 里是否存在 config.STORAGE_KEYS.TOKEN
    • 页面是否需要 auth.ensureLogin()
    • 是否误用了 silent 导致 401 没触发清理/引导
  • 样式不一致:
    • 是否使用了 .btn-resetbutton 默认样式会把你“设计稿一致性”破坏掉)
    • 是否使用了 .safe-bottom
    • 是否沿用了已有页面的卡片/按钮视觉语言