ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

微信小程序全栈开发实战:记录型工具从0到1的踩坑与沉淀

微信小程序全栈开发实战:记录型工具从0到1的踩坑与沉淀 简介在微信小程序开发中前后端分离架构已成为中大型项目的标配。其核心思想是将界面交互与业务逻辑解耦前端负责用户操作与渲染后端通过API提供数据服务同时需要处理登录鉴权、数据库设计、文件存储等关键链路。这种架构不仅提升了开发效率和代码可维护性还能灵活应对业务扩展。对于带图片上传功能的内容类小程序还需重点考虑直传对象存储、接口防刷与异常兜底。从电商到工具类应用前后端分离的实践模式已被广泛验证。本文以记录型工具小程序为例完整复盘其从V1.0.1到V1.0.39的演进过程涵盖Node.js后端选型、Token鉴权、数据库索引优化、性能调优及Docker部署等实战经验为同类型项目提供可直接落地的参考。 榆落微时光从 V1.0.1 一路迭代到 V1.0.39这个版本号放在小程序赛道上不算多惊人但足够把一个从零开始的“记录型工具”小程序真正打磨到敢给用户长期使用的状态。这个项目表面上只是“记录生活片段”可实际做起来牵扯到的却是小程序前端、后端服务、对象存储、数据库、部署运维一整条链路。很多人会问“小程序商城项目有没有参考价值”商城当然有价值但电商逻辑太重榆落微时光这种记录型工具反而更贴近大量非电商类微信小程序的真实需求——登录、动态列表、图片上传、数据统计、内容审核每一个模块都不浮夸但每一个模块都绕不开。如果你也想做一款前后端分离的小程序或者正在困扰“前端写完不知道后端该怎么搭”这篇文章值得你泡杯茶慢慢看。我会按这个版本下我们实际沉淀下来的通用方案来复盘小程序端用什么架构、后端为什么选 Node.js、表结构怎么设计、请求层怎么封装、V1.0.39 之前踩过的坑以及最后上线的部署和合规细节。这些内容不是某个框架的官方文档而是把项目拆开揉碎之后真正在线上跑过、也真正出过问题的经验。1. 榆落微时光这个项目的定位一个记录型工具小程序的完整样貌1.1 产品定位不做商城只做“微时光”记录榆落微时光的核心功能是让用户用“一张照片 一段文字 一个心情标签”记录当天的某个瞬间并把这些记录按时间轴和日历视图沉淀下来。项目名里“榆落”取的是微小日常的意象——时间不会停下来但我们可以留下一些细小的切片。这也决定了它和商城类小程序完全不同的技术侧重点。商城业务核心是商品、订单、支付、库存而榆落微时光的核心业务是内容生产、内容展示、用户长期留存。从代码层面看它要处理的是更常见的“用户登录—上传内容—列表展示—互动反馈”链路。很多人觉得这类工具简单但真正上手就会发现图片上传的稳定性、列表滚动性能、不同机型上的兼容性、后端接口的鉴权与防刷每一块都能写成一篇踩坑笔记。V1.0.39 这个版本号也说明了项目的发展节奏。V1.0.x 阶段意味着整体功能已经稳定后面的迭代不是推倒重来而是在一个相对成熟的骨架上不断做性能优化、兼容性修复和体验打磨。从 V1.0.1 到 V1.0.39核心模块没有大幅变更但分包结构调整了三次接口鉴权从“前端随便传 userId”改成了完整的 token 机制图片上传也从“先传后端再传对象存储”改成了“小程序直传对象存储”。这些变化才是版本号背后真正有价值的东西。1.2 核心功能模块拆解为了让你对项目有一个整体感知我先列出榆落微时光的主要功能模块以及每个模块在技术上对应的关键点模块用户侧功能技术关键词时光首页信息流展示历史记录支持分页加载列表分页、图片懒加载、下拉刷新记录发布拍照/相册选图、输入文字、选择心情wx.chooseMedia、canvas 压缩、上传直传日历回忆按月份查看哪几天有记录日历组件、日期聚合接口个人中心昵称头像、我的记录、设置用户隐私接口、本地缓存后台管理用户管理、内容审核、数据统计管理端鉴权、数据报表心情标签这个交互用到了微信小程序的 radio-group 单选框能力。初看很简单但如果你想做成一排圆形的表情选择器就需要在 radio 外部包一层自定义样式并且让选中的 value 和后端枚举严格对应。这类小细节在实战中非常容易出问题我后面会专门展开。1.3 前后端整体架构从请求到落库的完整链路榆落微时光前后端分离但小程序端和传统 Web 前端有一个很大区别微信小程序无法直接访问任意域名所有的请求域名必须在微信公众平台配置为合法域名并且必须走 HTTPS。所以整个链路是这样的小程序端发起 wx.request 请求请求到达 Nginx 接入层Nginx 将 /api 路径转发到 Node.js API 服务API 服务处理业务逻辑读写 MySQL 和 Redis图片文件则通过临时凭证直传对象存储不走 API 服务中转。后端服务本身拆成两个大块面向 C 端小程序的 API以及面向内部运营的管理端接口。管理端不放在小程序里而是单独一个 Web 页面通过账号密码登录后获取管理 token操作内容审核和数据查看。这样 C 端和管理端的 token 体系分开权限边界更清晰。2. 前端骨架原生框架选择、分包设计与请求层封装2.1 为什么坚持用原生小程序而不是 uni-app 或 Taro开发阶段我们讨论过要不要上跨端框架。最后决定用原生微信小程序核心原因是榆落微时光只投放微信端没有多端需求而原生框架对微信底层能力的支持是最直接的。举个例子微信后来的 Skyline 渲染引擎以及分包异步化、自定义导航栏、隐私保护接口这些新能力官方原生框架可以第一时间接入而跨端框架往往要等框架层适配。用原生还有一个好处微信开发者工具对原生代码的调试体验最完整wxml 的节点审查、Network 面板的请求查看、Storage 的可视化操作在原生项目里都是零损耗的。不是 uni-app 不好是对于“只做微信端”的项目多引入一层编译框架确实没必要。如果你有快手、抖音小程序等多端需求uni-app 或 Taro 是完全合理的选择但你要接受它们在个别平台能力上可能存在滞后。在渲染引擎的选择上我们也做了一次取舍。V1.0.39 版本里大部分页面仍然使用默认的 WebView 渲染只有信息流列表页开启了 Skyline 渲染。Skyline 在长列表滚动、手势动画上的表现更好但它和 WebView 的能力边界不完全一样比如部分 CSS 选择器支持程度不同。所以我建议不要把整个项目一次性迁到 Skyline而是挑选最适合的页面逐步切换出了问题影响面也可控。2.2 主包与分包控制包体是第一个性能瓶颈微信小程序规定主包不能超过 2MB整个小程序的上限根据不同基础库会放宽到 20MB 左右。但包体越大冷启动越慢用户在弱网环境下等待就越久。榆落微时光第一版把所有页面都塞进主包结果主包到了 1.9MB每次冷启动都让人紧张。后来我们做了一次彻底的分包调整主包tabBar 页面首页、记录、日历、个人中心以及公共组件和公共工具库分包A记录详情、记录编辑、图片预览分包B数据统计、关于、隐私协议等低频页面。结构调整之后主包降到 1.3MB冷启动明显加快。这里有一个关键点分包不是简单把页面文件夹移出去就完了页面之间的跳转路径会变tabBar 页面不能放在分包里某些组件跨分包使用也要注意。实际上微信的基础库后来支持了“分包异步化”也就是说在一个分包里可以通过异步 require 去使用另一个分包里的组件或逻辑这非常实用。// 在分包A的页面中异步获取分包B中的工具模块 let subpackageUtil null Page({ async onLoad() { // 先加载分包B再使用其中的模块 const loadTask wx.loadSubpackage ? wx.loadSubpackage({ name: packageB }) : Promise.resolve() if (loadTask loadTask.then) { await loadTask.catch(() wx.showToast({ title: 资源加载失败请重试 })) } subpackageUtil require(../../packageB/utils/sharedModule/common.js) } })这种做法可以让页面先快速渲染出来再异步加载低频功能所需的分包尤其适合“首页很轻、详情页较重”的产品形态。不过要注意低版本基础库不支持 loadSubpackage 时需要有降级处理否则会把整个包体一次性下载回来。2.3 请求层封装统一处理登录态、401 和错误提示小程序开发中最容易被忽视也最影响长期维护质量的就是请求层。如果每个页面都直接写 wx.request代码会迅速失控。榆落微时光的请求封装很早就定了核心思路是所有请求走同一个入口由入口统一携带 token、统一处理 HTTP 状态码、统一在业务 code 非 0 时弹出错误提示。const BASE_URL https://api.example.com/api function refreshToken() { return new Promise((resolve, reject) { wx.request({ url: ${BASE_URL}/auth/refresh, method: POST, header: { Authorization: Bearer ${wx.getStorageSync(refreshToken)} }, success: (res) { if (res.data res.data.code 0) { wx.setStorageSync(token, res.data.data.token) wx.setStorageSync(refreshToken, res.data.data.refreshToken) resolve(res.data.data.token) } else { reject(res) } }, fail: reject }) }) } function request(url, options {}) { const token wx.getStorageSync(token) const header { Content-Type: application/json, Authorization: Bearer ${token}, ...(options.header || {}) } return new Promise((resolve, reject) { wx.request({ url: ${BASE_URL}${url}, method: options.method || GET, data: options.data || {}, header, success: (res) { // 登录态失效 if (res.statusCode 401) { refreshToken() .then(() request(url, options)) .then(resolve) .catch(() { wx.reLaunch({ url: /pages/index/index }) reject(res) }) return } const body res.data if (body body.code 0) { resolve(body.data) } else { if (options.showError ! false) { wx.showToast({ title: (body body.message) || 请求失败, icon: none }) } reject(body) } }, fail: (err) { wx.showToast({ title: 网络异常请检查网络, icon: none }) reject(err) } }) }) }一个容易出现的问题是多个请求同时返回 401就会触发多次 refreshToken。解决办法是给刷新操作加一个 Promise 单例在刷新过程中后续的 401 请求都等待同一个刷新任务完成而不是各自重新刷新。这个小细节不处理线上会出现“登录态刷新风暴”用户会莫名其妙被踢下线。2.4 组件与工具沉淀导航栏高度、单选框与地图选型榆落微时光里有很多看起来不起眼、实际容易翻车的组件细节。第一个是自定义顶部导航栏。很多页面为了沉浸式体验会设置 navigationStyle: custom然后用自定义组件填充顶部。但微信小程序的胶囊按钮位置在不同机型上不一样不能写死一个高度。正确做法是通过 wx.getMenuButtonBoundingClientRect 获取胶囊按钮的位置信息再用 window 信息计算出导航栏高度和状态栏高度动态应用到页面上。这个高度在 iOS 和安卓上是不同的测试时一定要找一台安卓低端机看效果。第二个是单选框。微信小程序的 radio-group 组件本身能力没问题但默认样式非常朴素。榆落微时光的心情标签需要做成多个圆形表情图点击后高亮。我们的做法是隐藏原生 radio用 view 模拟选中状态再用一个隐藏的 radio-group 保存当前选中值。这里有个经验隐藏 radio 时不要用 display: none否则部分安卓机型在表单提交时拿不到值最好用绝对定位移出可视区域但不销毁组件。第三个是地图选型。很多人问过“微信小程序可以使用天地图地图组件吗”。结论比较明确原生 map 组件底层由微信统一封装并不支持直接切换成天地图数据源。如果只是做普通位置展示直接用原生 map 组件就够了如果业务必须用到天地图的影像或特定瓦片资源那就只能通过 web-view 嵌入天地图网页版但体验、交互和用户身份打通都要自己处理。榆落微时光目前没有强地图需求所以不引入地图 SDK也少了一堆授权弹窗的兼容问题。3. 后端设计选型、表结构、鉴权与图片上传3.1 后端技术栈为什么是 Node.js Express TypeScript后端选型时我们做了三组对比。很多人提到 ruoyi 这类 Java 框架它确实在企业级权限系统里很强菜单权限、用户体系、代码生成都是现成的但榆落微时光这种轻量记录型小程序后端只需要几十个接口用 Spring Boot 跑起来相当于“杀鸡用牛刀”而且部署时对服务器内存的压力更大。NestJS 是一个更工程化的 Node.js 框架适合中大型项目但对于我们这种规模Express 加 TypeScript 就足够核心接口保持清晰方便后续演进。技术栈优势劣势适用场景Express TypeScript轻量、灵活、前端可维护工程规范需要自己约束中小型项目NestJS模块化、依赖注入、规范强学习成本和样板代码较多中型以上项目Spring Bootruoyi 等企业级权限体系成熟启动重、服务器成本高复杂企业后台最终落地的后端结构大致如下server/ src/ modules/ user/ # 用户模块登录、资料 moment/ # 记录模块发布、列表、日历 upload/ # 上传模块生成临时凭证 admin/ # 管理端审核、统计 common/ middlewares/ # 鉴权、日志、错误处理 utils/ # 加解密、分页工具 app.ts # Express 实例 config.ts # 环境配置 Dockerfile docker-compose.yml这里有一个非常实用的经验从第一天就引入 TypeScript不要等到项目中期再迁移。JS 写路由和简单业务确实是爽但是等接口变多、数据结构变复杂后你再回想一个对象里到底有哪些字段真的会崩溃。TypeScript 的 interface 在这个阶段给你的帮助是几何级数的。3.2 数据表设计用户表与记录表是核心榆落微时光的表结构不算复杂但设计时还是踩过索引的坑。核心表是 user 和 moment。CREATE TABLE user ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, openid VARCHAR(64) NOT NULL, unionid VARCHAR(64) DEFAULT , nickname VARCHAR(64) DEFAULT , avatar_url VARCHAR(255) DEFAULT , status TINYINT NOT NULL DEFAULT 1 COMMENT 1正常 0禁用, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE moment ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, user_id INT UNSIGNED NOT NULL, content VARCHAR(500) NOT NULL DEFAULT , images JSON NOT NULL COMMENT 图片URL数组, mood VARCHAR(16) DEFAULT COMMENT 心情标签, record_date DATE NOT NULL COMMENT 记录日期, status TINYINT NOT NULL DEFAULT 1 COMMENT 1正常 0隐藏, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_date (user_id, record_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;我在初版没给 moment 表加联合索引结果用户记录多了之后首页时间轴按 userId 倒序查询非常慢。后来加了 (user_id, record_date) 联合索引情况立刻好转。这里也提醒你JSON 字段在 MySQL 里操作并不方便如果后续需要对图片数量做统计尽量把图片数量单独拆成列不要每次都去 JSON 里解析。3.3 鉴权与登录态从 wx.login 到可主动失效的 token小程序的登录流程和普通 Web 不一样。前端调用 wx.login 拿到的是临时 code后端用这个 code 向微信接口换取 openid 和 session_key。注意openid 是用户在当前小程序下的唯一标识不要拿它当密码也不要直接暴露给前端。后端换到 openid 后会查询或创建用户然后签发两个 tokenaccessToken短期有效比如 2 小时小程序请求时放在 Authorization 头里refreshToken长期有效比如 14 天专门用来刷新 accessToken。这些 token 我们选择存 Rediskey 为 userIdvalue 为当前有效的 token。这么做的好处是服务端可以主动让某个用户的 token 失效——当用户被封禁、换设备登录、或者账号状态异常时直接删除 Redis 里的对应关系比纯 JWT 方案更容易控制。纯 JWT 在“服务端主动踢人”这个场景上很被动因为只要它没过期就永远有效。另外有一点必须提到现在微信对用户头像昵称的获取方式已经改了wx.getUserProfile 不再返回真实的头像和昵称替代方案是让用户在小程序内主动填写昵称、选择头像。这既是平台规则也是用户隐私保护的实际需要。后端接口设计上不要把“昵称头像”当成登录的必填参数登录只需要 code用户资料的完善可以在个人中心单独引导。3.4 图片上传临时凭证直传对象存储榆落微时光发布记录时最怕的就是用户选了几张高清原图上传卡在半路。如果把图片先传到 Node 后端再由后端转发到对象存储接口会长时间占用服务器带宽也会被打满。所以我们改成了“小程序直传对象存储”的方案小程序端先调后端接口获取临时上传凭证凭证里包含对象存储的 bucket、地域、临时密钥、过期时间小程序端直接用临时凭证把图片上传到对象存储上传成功后把图片 URL 随记录内容一起提交。这个方案的另一个好处是安全性。临时凭证过期时间很短即使被泄露影响窗口也有限。上传时还要注意小程序端在真实场景中应先用 canvas 压缩图片再上传。微信拿到的原图可能 5MB 甚至 10MB一张照片压缩到宽 1920、质量 80体积能控制在 500KB 左右用户上传体验和对象存储成本都能大幅改善。4. 迭代到 V1.0.39性能优化与真机兼容踩坑记录4.1 setData 优化的三个层次直接决定列表页卡不卡小程序前端的性能瓶颈90% 出在 setData 上。逻辑层和渲染层之间是通过数据通信的setData 的数据量越大、调用越频繁页面就越卡。榆落微时光在列表页踩过一个大坑一页加载 20 条记录每条记录包含好几张图片 URL、文案、时间当时直接 setData 整个数组在安卓中端机上滑动列表掉帧严重。第一个层次是减少单次 setData 的数据量。分页加载时不要拼接整个数组再一次性 setData而是用 concat 之后也只传新增的那部分配合页面 data 里的数组变量保持增量更新。第二个层次是使用局部路径更新。比如只需要修改某一条记录的点赞状态不要重新 setData 整个列表而是this.setData({ [momentList[${index}].liked]: true })第三层次是拆分组件。把列表中的每一项抽成独立组件并且给组件传入最小必要数据这样某一项内部状态变化时只更新那一个组件而不是整页。做到这三个层次之后榆落微时光的列表滚动流畅度提升非常明显。4.2 首屏加载提速的几个实际动作针对记录型工具用户体验关键在于冷启动和首屏。我们做了四件事每件事都不复杂合起来效果很突出。第一页面 onLoad 里用 Promise.all 并行请求首页所需的数据而不是一个接口一个接口串行等待。第二列表接口改成游标分页不传 page 页码而是传 lastId上一页最后一条记录的 ID这样新增数据时不会导致分页数据错位。第三图片 URL 统一走对象存储的图片处理参数比如缩略图模版列表页只加载宽度 400px 的小图详情页再加载原图。第四对某些低频分包做预下载在用户进入首页并稳定之后调用 wx.preloadSubpackage 提前下载统计分包这样用户真正点进统计页时基本不会有加载白屏。4.3 真机兼容问题iOS 键盘遮挡与安卓蓝牙适配V1.0.39 之前我们在真机兼容上花的时间比开发新功能还多。一个高频问题是 iOS 上键盘弹起时遮挡输入框。微信官方配置里有一个 adjust-position 属性默认在键盘弹起时上推页面但实测在某些 iOS 版本上会失效。我们的兜底方案是手动监听键盘高度变化把输入框滚动到可视区域。wx.onKeyboardHeightChange((res) { if (res.height 0) { // 输入框需要上移的高度根据页面元素位置动态计算 this.setData({ keyboardHeight: res.height }) } else { this.setData({ keyboardHeight: 0 }) } })另一个很多人问的是安卓 14 上小程序蓝牙模块的连接问题。榆落微时光早期版本做过一个“蓝牙打卡”的辅助功能踩过的坑主要是安卓 12 之后的权限模型更严格蓝牙扫描必须先动态申请定位权限和附近设备权限BLE 设备的扫描回调在某些国产 ROM 上有延迟不能只用 onBluetoothDeviceFound 无限等待要加上超时判断。如果你没有蓝牙需求这段可以跳过但如果你准备做智能硬件类小程序一定要在权限申请时机和超时处理上多留几个心眼。4.4 异常监控与告警从“用户说打不开”到主动发现线上问题最怕的不是 bug而是用户碰到问题之后你没有一点感知。榆落微时光在 V1.0.39 期间接入了轻量级错误上报前端在小程序 app.js 里监听 onError 和 onUnhandledRejection把错误信息、页面路径、机型、系统版本通过一个独立接口上报到后端后端记录错误日志同时在接口耗时异常时打点告警。还有一类问题是前端请求到了后端但后端处理超时。我们给所有外部依赖都设置了超时时间并在请求失败时做了指数退避重试。不要小看这个设计线上偶发请求失败如果下一秒所有用户同时重试会把后端打挂。指数退避配合 jitter随机抖动能把重试风暴的概率降得很低。5. 前后端分离的小程序从开发到发布部署、合规与备份5.1 本地开发环境的几个关键点本地跑这个项目时最容易犯的错误是“在小程序开发者工具里勾选不校验合法域名”然后开发完就忘了。这个选项只适合本地调试上线前一定要到微信公众平台把 API 域名和 uploadFile 合法域名都配上并且域名必须是 HTTPS。本地联调时我们一般不用“本地代理”那套复杂配置而是让后端服务监听局域网 IP小程序开发者工具直接请求 http://192.168.x.x:3000同时勾选本地不校验域名。手机预览时手机和电脑连同一个局域网把 BASE_URL 改成电脑 IP 即可。测试环境、生产环境的配置一定要拆开用环境变量控制避免上线时忘了切换地址所有请求打到测试库还把数据写乱了。5.2 用 Docker Compose 编排整套后端环境榆落微时光的后端部署用 Docker Compose 管理这是目前中小型前后端分离项目最省心的一套方案。相关服务包括 Nginx、API 服务、MySQL、Redis一次 docker compose up -d 就能全部起来。version: 3.8 services: nginx: image: nginx:1.24-alpine ports: - 80:80 - 443:443 volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro - /etc/letsencrypt:/etc/letsencrypt:ro depends_on: - api restart: always api: build: ./server environment: - NODE_ENVproduction - MYSQL_HOSTmysql - MYSQL_PORT3306 - MYSQL_USERyulu_app - MYSQL_PASSWORDplease_use_env_file - REDIS_HOSTredis ports: - 3000:3000 restart: always depends_on: - mysql - redis mysql: image: mysql:8.0 environment: - MYSQL_DATABASEyulu_microtime - MYSQL_USERyulu_app - MYSQL_PASSWORDplease_use_env_file - MYSQL_ROOT_PASSWORDplease_use_env_file volumes: - ./data/mysql:/var/lib/mysql restart: always redis: image: redis:7-alpine volumes: - ./data/redis:/data restart: always这里要特别提醒生产环境不要把这些密码直接写死在 docker-compose.yml 里应该用 .env 文件管理并将 .env 加入 .gitignore。还有一个很容易忽略的问题MySQL 容器升级镜像时如果数据卷配置不对可能造成数据丢失。所有数据库文件都要挂载到宿主机目录并且定期备份。5.3 Nginx 层要做的事HTTPS、路径转发与静态资源缓存Nginx 在这里承担了整套环境的入口。小程序要求所有请求域名必须是 HTTPS所以 Nginx 层必须配置好证书并把 443 端口收到的请求转发到 API 容器。server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; location /api/ { proxy_pass http://api:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }注意proxy_pass 后面的地址使用了 api这是 Docker Compose 服务名在同一个网络内可以直接访问。Nginx 还会帮我们做一层访问控制比如限制上传接口的单 IP 请求频率防止有人用脚本恶意刷图。这个在公网环境下还是挺重要的。5.4 发布前的合规与运营细节小程序上线前有一堆和代码无关但必须处理的事情漏掉任何一个都会被审核打回。榆落微时光是记录类工具类目选择上属于工具类别不涉及在线播放、观看服务所以不需要选择文娱视频类目。如果你的小程序涉及视频播放或直播那就要提前补充“文娱-其他视频类目”以及对应的资质材料这点审核卡得非常严格。另外几个容易被忽略的运营细节ICP 备案和域名备案小程序 API 域名必须完成备案而且小程序本身也需要完成平台侧的备案流程用户隐私保护指引微信后台要求填清楚收集哪些用户信息小程序代码里调用 wx.getPrivacySetting 判断用户的隐私授权状态不能用“一刀切”方式强制获取订阅消息如果要做“明天提醒”之类的服务提前在后台申请订阅消息模板测试号也有次数限制灰度发布微信公众平台支持分阶段发布实践下来最稳妥的方式是先 5%观察线上错误率和用户反馈再逐步放量到全量。5.5 数据备份与回滚把事故变成小麻烦任何项目做到后期都必须把“万一挂了怎么办”当成一个正式需求来对待。榆落微时光的数据备份策略很朴素但很有效每天凌晨通过 cron 使用 mysqldump 备份整个数据库保留最近 7 天对象存储本身有服务商提供的高可用和版本管理不额外处理后端镜像在构建时打上版本 tag比如 api:v1.0.39发布新版本时如果发现严重问题可以直接 docker compose 指定旧镜像回滚。前端的回滚更简单微信公众平台支持把线上版本回退到任意一个历史审核通过版本。但前提是后端接口要做向前兼容所以一个原则是后端先发布新接口保留旧接口一段时间等小程序新版本覆盖率达到预期后再下线旧接口。这个习惯能避免很多“前端没更新完后端已经删了字段”的线上事故。把一个小程序从原型做到 V1.0.39最大的收获不是这个版本号本身而是把一个又一个“看着没问题”的隐患变成了“确定没问题”的方案。记录型小程序的技术难度不在于某个刁钻的算法而在于每一个环节的数据流是否清晰、每一类异常情况是否有兜底、每一次发布是否有回退路径。我个人比较深的体会是这类项目一定要把请求层封装做干净、把后端鉴权想透、把部署流程固化下来否则每次改需求都会像在补一个不断扩大的窟窿。如果你也正在维护一个前后端分离的小程序建议先把这几个基础问题解决好再谈加功能和换框架。项目稳定跑上一年之后你会发现当初在这些“枯燥”环节上花的时间才是回报率最高的投入。本文还有配套的精品资源点击获取
返回列表