← 全部文章
架构跨端技术选型uni-appLBS

从 0 设计「附近免费好物」多端应用:小程序 + App 全平台选型与架构

2026年7月28日 · 18 分钟

先把产品需求翻译成工程语言

我们要做的产品,对标海外的 Snag:帮用户发现身边别人免费送出的物品(家具、家电、日用品),聚合成一个信息流,用户浏览、筛选、收藏、领取。落到中国区,还叠加了三条硬约束:

  • 多端框架:一套代码尽量覆盖尽可能多的端;
  • 发布小程序到各平台:微信、支付宝、抖音、百度、QQ、快手;
  • 多平台账号登录 + 独立 App(iOS / Android)。

把它拆成技术命题:

产品能力背后的技术需求
看"附近"的免费物品LBS 地理空间检索(按距离排序/半径过滤)
用户自己发布物品UGC + 图片/视频上传 + 内容审核
一个信息流刷不停分页/游标、Feed 排序、缓存
收藏、领取、订阅付费账号体系、订单/权益、支付
全平台小程序 + App跨端框架 + 多端登录打通
中国区上线备案、实名、内容合规

一句话定性:这是一个 LBS + UGC + 内容分发 + 订阅付费的消费级应用。 记住这个定性,后面每个选型都为它服务。

最关键的一个判断:这是一个「附近」应用

很多人上来就纠结用 Vue 还是 React,其实决定架构的心脏是"附近"两个字。"查我周围 3 公里内的物品,按距离排序"——这类地理空间查询,直接决定了数据库选型(下文第五节会给出 PostGIS 方案)。先把这个钉子钉住,其余都是围绕它的工程组织。


一、跨端框架选型:为什么是 uni-app

需求里"发全平台小程序 + App"这一条,直接把候选框架砍到了很短的名单。我们逐个对比:

框架小程序(微信/支付宝/抖音/百度…)App(iOS/Android)语言/生态中国本土化上手结论
uni-app✅ 全平台官方支持,覆盖最全✅ 原生渲染打包 / uni-app xVue,DCloud★★★★★主选
Taro✅ 支持主流小程序✅ 走 React NativeReact(也支持Vue),京东★★★★React 团队备选
Flutter❌ 无官方小程序方案(mpflutter 不成熟)✅ 体验最好Dart★★★有小程序需求直接出局
React Native❌ 不能编译小程序React★★★缺小程序,出局
各端原生每端各写一遍✅ 最优多套成本爆炸,出局

判断逻辑

  1. 需求明确要"发到各家小程序",Flutter / RN 当场出局——它们没有小程序编译目标。
  2. 剩下 uni-app 和 Taro,两者都能"一套代码 → 多端小程序 + App"。
  3. 选 uni-app 的理由
    • 多端覆盖最全,微信/支付宝/抖音/百度/QQ/快手小程序官方一线支持,中国区小程序生态踩坑最少;
    • App 端方案成熟:可直接打包为原生 App,性能敏感页面用 uni-app x(uts 语言,接近原生渲染)补足;
    • 插件市场 + 中文文档 + 社区在国内最厚,登录/支付/地图这些"中国特色"能力有大量现成轮子;
    • 团队招 Vue 开发者比 Dart 容易。
  4. 什么时候选 Taro:如果团队是重度 React 栈、且已有 React 组件资产要复用,Taro 更顺手;App 端走 RN 性能也不错,代价是配置更重、小程序踩坑略多。

结论:默认 uni-app(Vue3 + TS + Vite);纯 React 团队可换 Taro,架构其余部分不变。


二、客户端架构与「一套代码多端」的关键手段

uni-app 客户端
├── pages/            页面(首页 Feed、附近、详情、发布、我的)
├── components/       跨端复用组件
├── stores/           Pinia 状态管理(用户、位置、Feed)
├── api/              请求层(统一拦截器:注入 token、错误处理)
├── utils/platform    平台差异封装(登录/支付/定位)
└── #ifdef 条件编译    抹平各端 API 差异

多端最大的痛点是各端 API 不一样(微信是 wx.、支付宝是 my.、App 是 plus.)。uni-app 用两招解决:

  • 统一 API:绝大多数能力用 uni. 前缀,框架帮你翻译到各端;
  • 条件编译 #ifdef:处理无法统一的部分,比如登录:
// utils/login.js —— 同一个函数,各端走各端的登录
export async function platformLogin() {
  // #ifdef MP-WEIXIN
  const { code } = await uni.login({ provider: 'weixin' });
  return exchangeToken('wechat-mp', code);
  // #endif

  // #ifdef MP-ALIPAY
  const { code } = await uni.login();
  return exchangeToken('alipay-mp', code);
  // #endif

  // #ifdef APP-PLUS
  const res = await uni.login({ provider: 'weixin' }); // App 拉起微信
  return exchangeToken('wechat-app', res.authResult);
  // #endif
}

上层业务只调 platformLogin(),不用关心跑在哪个端。


三、多平台登录体系(本项目最容易踩坑的一块)

"支持各平台登录"不是简单接几个 SDK,核心难点是:同一个人从不同端进来,要能识别成同一个账号。设计分两步。

3.1 各端登录方式矩阵

运行端登录方式客户端拿到什么后端如何处理
微信小程序uni.logincode用 code 调 code2session 换 openid + unionid
支付宝小程序getAuthCodeauthCode换 alipay userId
抖音小程序tt.logincode换 open_id
百度/QQ/快手小程序各端 logincode换对应 open_id
App(微信登录)微信开放平台authCode换 openid + unionid
App(iOS 必接)Sign in with AppleidentityToken校验拿 apple user id
全端兜底手机号一键登录 / 短信验证码手机号作为主账号锚点

上架 iOS 有第三方登录时,Apple 强制要求同时提供 Sign in with Apple;手机号务必接入,它是打通所有身份的"锚点"。

3.2 统一账号模型(一个用户,多个身份)

后端不要直接用微信 openid 当用户 ID,而是抽象出"用户"和"身份"两张表:

-- 用户主体
CREATE TABLE users (
  id           BIGSERIAL PRIMARY KEY,
  phone        VARCHAR(20) UNIQUE,        -- 手机号锚点
  nickname     VARCHAR(64),
  created_at   TIMESTAMPTZ DEFAULT now()
);

-- 第三方身份,一个 user 可绑定多个
CREATE TABLE user_identities (
  id         BIGSERIAL PRIMARY KEY,
  user_id    BIGINT REFERENCES users(id),
  provider   VARCHAR(32),   -- wechat / alipay / apple / douyin ...
  open_id    VARCHAR(128),  -- 该平台内的唯一 id
  union_id   VARCHAR(128),  -- 微信生态跨应用打通用
  UNIQUE(provider, open_id)
);

打通逻辑

  • 微信系(小程序 + App + 公众号)用 UnionID 归并——只要在同一微信开放平台账号下,UnionID 一致即同一人;
  • 其它端登录后,引导绑定手机号,用手机号把不同 provider 的身份挂到同一个 users.id
  • 后端统一签发自己的 JWT,客户端所有请求只认这个 token,与具体登录方式解耦。

这样无论用户用微信小程序还是 App 微信登录进来,看到的都是同一份收藏和数据。


四、后端技术选型

方案优势劣势适用
NestJS(Node/TS)与前端同语言,全栈 TS,生态足,开发快CPU 密集型偏弱主选
Go(Gin/Kratos)高并发、低延迟、部署简单生态/开发效率略逊LBS/Feed 热点服务
Spring Boot(Java)企业级成熟、稳重、启动慢、人力贵大厂/已有 Java 团队

选型结论

  • 主体用 NestJS:与 uni-app 的 TS 前端同一套语言与类型,能共享 DTO/校验模型,中小团队研发效率最高,模块化架构(Module/Provider/Guard)天然适合分层;
  • 对性能敏感的"附近 Feed"服务,可用 Go 单独拆一个微服务:这是读多写少、并发最高的接口,Go 的并发模型能扛住热点。

初期不必上重微服务,先用 NestJS 模块化单体(用户/物品/LBS/审核/订单各一个 module),流量起来后再把 LBS 服务拆出去,避免过早优化。


五、数据与存储:LBS 是核心

5.1 主数据库:PostgreSQL + PostGIS

"查附近物品"是心脏功能,所以数据库首选 PostgreSQL + PostGIS 扩展——它有成熟的地理空间类型和索引:

CREATE EXTENSION postgis;

CREATE TABLE items (
  id        BIGSERIAL PRIMARY KEY,
  title     TEXT,
  user_id   BIGINT,
  status    SMALLINT,               -- 审核/上架状态
  geom      GEOGRAPHY(POINT, 4326), -- 经纬度
  created_at TIMESTAMPTZ DEFAULT now()
);

-- 地理空间索引,让"附近查询"走索引而非全表扫描
CREATE INDEX idx_items_geom ON items USING GIST (geom);

查"我周围 3 公里、已上架的物品,按距离排序":

SELECT id, title,
       ST_Distance(geom, ST_MakePoint(:lng, :lat)::geography) AS dist
FROM items
WHERE status = 1
  AND ST_DWithin(geom, ST_MakePoint(:lng, :lat)::geography, 3000)
ORDER BY dist
LIMIT 20;

为什么不用 MongoDB:我们需要事务(下单/领取)、关系(用户-物品-身份)和成熟的地理检索,PostgreSQL + PostGIS 一站式满足,比拼装方案更省心。

5.2 其余存储分工

组件选型职责
缓存/会话Redistoken、热点 Feed、限流、附近热区缓存
图片/视频对象存储(腾讯云 COS / 阿里云 OSS) + CDNUGC 媒体,前端直传 + 回源审核
搜索/筛选Elasticsearch(可选)关键词、多条件筛选;初期可用 PG 全文顶着
消息队列Kafka/RocketMQ(可选)异步审核、通知、埋点解耦

六、整体系统架构

        ┌──────────────────────────────────────────────┐
        │  客户端(uni-app 一套代码)                     │
        │  微信/支付宝/抖音/百度/QQ/快手 小程序 + iOS/Android App │
        └───────────────────────┬──────────────────────┘
                                 │ HTTPS
                     ┌───────────▼───────────┐
                     │   CDN + API 网关/BFF   │  鉴权、限流、路由
                     └───────────┬───────────┘
             ┌───────────────────┼───────────────────┐
        ┌────▼────┐   ┌────▼────┐   ┌────▼────┐  ┌────▼────┐
        │ 用户服务 │   │ 物品服务 │   │ LBS/Feed │  │ 审核服务 │
        │(登录/账号)│   │(发布/详情)│   │(附近查询)│  │(内容合规)│
        └────┬────┘   └────┬────┘   └────┬────┘  └────┬────┘
             └──────┬───────┴─────┬───────┴────────────┘
              ┌─────▼─────┐ ┌─────▼─────┐ ┌──────────┐ ┌─────────┐
              │PostgreSQL │ │  Redis    │ │对象存储OSS│ │ ES(可选)│
              │ +PostGIS  │ │(缓存/会话)│ │  +CDN    │ │ (搜索)  │
              └───────────┘ └───────────┘ └──────────┘ └─────────┘

要点:客户端只面对统一的 BFF/网关,各端登录差异在客户端 #ifdef 里消化、在用户服务里归并,其余服务完全不感知调用来自哪个端。


七、中国区合规:不能省的一节

海外照抄一套技术就上线,在国内会直接被下架。作为专家必须提醒三件事:

  1. 内容安全审核(最硬性):UGC 的图片和文字必须审核。接入腾讯云/阿里云的内容安全服务,做"机审兜底 + 高危先审后发"。这是 UGC 产品能否活下来的红线。
  2. 备案与资质:域名 ICP 备案;各家小程序对"信息发布/二手交易"类目有资质要求,提交前先查平台类目规范。
  3. 实名与隐私:遵循《个人信息保护法》,发布隐私政策、遵循最小必要原则收集信息,敏感权限(定位)要有明确授权引导。

八、部署与 DevOps

  • 容器化:整套后端用 Docker 打包(正好呼应本站的 Docker 系列),环境一致、随处可跑;
  • 编排:流量起来后上 Kubernetes 做弹性伸缩,"附近 Feed"高峰可单独扩容;
  • CI/CD:GitHub Actions / GitLab CI,推代码自动构建镜像并部署;
  • 云厂商:优先腾讯云或阿里云(内容审核、短信、对象存储、地图一站式配齐,且合规链路顺);
  • 可观测:日志 + 指标 + 链路追踪,尾延迟和错误率必须能看见。

选型总览

层次选型一句话理由
跨端框架uni-app(Vue3+TS)全平台小程序覆盖最全,App 方案成熟,中国区踩坑最少
状态管理Piniauni-app/Vue3 官方推荐,轻量
后端NestJS(+ Go 拆热点)与前端同 TS,开发快;高并发接口用 Go 补
主数据库PostgreSQL + PostGIS"附近查询"是心脏,地理索引一站式满足
缓存Redis会话、热点 Feed、限流
媒体对象存储 + CDNUGC 图片/视频直传与分发
搜索Elasticsearch(可选)多条件筛选;初期 PG 全文顶替
登录多 provider + UnionID/手机号归并统一账号模型,一人多身份
部署Docker + K8s + 腾讯云/阿里云环境一致、弹性伸缩、合规链路完整

小结

  • 先给产品定性(LBS + UGC + 订阅),再让每个选型为它服务;
  • 有"全平台小程序 + App"这条,跨端框架实际只在 uni-app / Taro 里二选一,默认 uni-app;
  • 登录不是接 SDK,而是设计**"一人多身份"的统一账号模型**,用 UnionID + 手机号归并;
  • 数据库因"附近"而定:PostgreSQL + PostGIS
  • 中国区的内容审核与备案是必须提前规划的红线,不是上线后再补的功能。

按这套方案,你可以用一支不大的 Vue/TS 团队,一套代码把小程序全平台 + iOS/Android App 都覆盖掉,把精力真正花在"帮用户找到身边好物"这件事上。

相关水晶