8.8 KiB
小程序前端开发与后端 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_URLCURRENT_ENVREQUEST_TIMEOUT(默认 30s)PAGE_SIZE(默认 20)STORAGE_KEYS(token/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/jsonAuthorization: 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.js 和 app.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.js 的 uploadFile():
- 上传地址:
${config.API_BASE_URL}/upload - 携带
Authorization: Bearer <token> - 支持
formData.folder指定目录 - 兼容多种返回格式(
{code:0}或{success:true})
7.2 图片 URL 拼接
后端返回相对路径时,用 utils/imageUrl.js 的 getFullImageUrl() 拼成完整地址(基于 API_BASE_URL 去掉 /api)。
8. 头部与页面结构(统一样式框架)
工程里常见的头部结构是“固定导航 + 状态栏占位 + 标题 + 返回按钮”:
- 导航容器:
nav-container - 状态栏占位:
status-bar - 导航栏:
nav-bar - 返回按钮:
nav-back - 标题:
nav-title
常见页面结构示例可参考:
- 提现页:
pages/withdraw/withdraw.wxml、pages/withdraw/withdraw.wxss - 充值页:
pages/recharge/recharge.wxml - 提现记录:
pages/withdraw-records/withdraw-records.wxml
建议实践:
- 导航容器固定(fixed),内容区通过
padding-top: {{totalNavHeight}}px或padding-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 页面级常用视觉语言
在本项目里,“一致感”主要来自以下元素:
- 背景:浅紫/粉色系渐变或纯色(如
#E8C3D4、linear-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 的推荐流程
- 在
utils/api.js增加/修改对应模块方法(保持命名与路径一致) - 请求一律通过内部
request()(确保 header、401、timeout、错误格式一致) - 页面侧只调用
api.xxx.yyy(),不直接拼 URL、不直接wx.request - 异常统一走
handleApiError,少在页面写自定义错误文案
12. 排查清单(定位问题最快)
- 请求没到后端:
config.CURRENT_ENV是否正确config.API_BASE_URL是否正确(是否带了/api)- 是否混用了
utils_new导致 baseUrl/token 读取来源不一致
- 401/未登录:
- storage 里是否存在
config.STORAGE_KEYS.TOKEN - 页面是否需要
auth.ensureLogin() - 是否误用了 silent 导致 401 没触发清理/引导
- storage 里是否存在
- 样式不一致:
- 是否使用了
.btn-reset(button 默认样式会把你“设计稿一致性”破坏掉) - 是否使用了
.safe-bottom - 是否沿用了已有页面的卡片/按钮视觉语言
- 是否使用了