一、架构设计概览
核心思想: 前后端分离 (Decoupled Architecture)
- uni-app 作为前端框架,负责渲染所有用户界面(H5、小程序、App),并通过 HTTP API 与后端交互。
- ThinkPHP 作为后端框架,提供 RESTful API,处理业务逻辑、数据存储、安全性、并发等。
- 两者通过 JSON 格式的数据进行通信。
架构图:
text
[H5 | 微信小程序 | App | 其他平台] (基于 uni-app)
| (HTTP/HTTPS + JSON)
|
[API 网关 (可选) | Nginx] (反向代理、负载均衡)
|
[ThinkPHP API 服务器] (核心业务逻辑)
|
[MySQL (主数据)] [Redis (缓存/会话/队列)] [Elasticsearch (搜索)] [OSS/COS (文件存储)]
二、技术栈选型与职责
| 层级 | 技术 | 职责 |
|---|---|---|
| 前端 (uni-app) | Vue.js 语法、Vuex(状态管理)、uni-ui 或 uView UI(组件库) | 渲染页面、用户交互、调用API、管理本地状态(如购物车) |
| 后端 (ThinkPHP) | ThinkPHP 6.x+(API开发模式)、JWT(令牌认证)、Redis、Elasticsearch | 提供RESTful API、用户认证、订单处理、支付回调、数据管理 |
| 数据与存储 | MySQL(主数据库)、Redis(缓存、秒杀)、阿里云OSS/腾讯云COS(文件存储) | 数据持久化、高性能访问、静态资源存储 |
| 部署与运维 | Nginx(Web服务器)、Linux、Docker(容器化,可选) | 服务部署、负载均衡、反向代理 |
三、核心功能模块设计与实现
1. 前后端数据交互规范
首先,必须定义一套统一的 API 响应格式,这是前后端协同开发的基础。
ThinkPHP 控制器示例:
php
<?php
namespace app\api\controller;
use think\Response;
class BaseController
{
// 成功返回
protected function success($data = null, $msg = 'success', $code = 200)
{
return Response::create([
'code' => $code,
'msg' => $msg,
'data' => $data
], 'json');
}
// 失败返回
protected function error($msg = 'error', $code = 400, $data = null)
{
return Response::create([
'code' => $code,
'msg' => $msg,
'data' => $data
], 'json');
}
}
uni-app 请求封装示例 (使用 uni.request):
javascript
// utils/request.js
import { baseUrl } from '@/config/config.js';
const request = (options) => {
return new Promise((resolve, reject) => {
uni.request({
url: baseUrl + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
'Authorization': uni.getStorageSync('token') // 从本地存储获取JWT Token
...options.header
},
success: (res) => {
if (res.data.code === 200) {
resolve(res.data);
} else {
// token过期等统一处理
if (res.data.code === 401) {
uni.navigateTo({ url: '/pages/login/login' })
}
uni.showToast({ title: res.data.msg, icon: 'none' });
reject(res.data);
}
},
fail: (error) => {
reject(error);
}
});
});
};
export default request;
2. 用户认证与授权 (JWT)
-
流程: 用户登录 -> ThinkPHP 验证账号密码 -> 生成 JWT Token -> 返回给 uni-app -> uni-app 存储 Token 并在后续请求头中携带。
-
ThinkPHP 生成 JWT:
php
use Firebase\JWT\JWT; // 使用composer安装firebase/php-jwt public function login() { $username = input('username'); $password = input('password'); // 1. 验证用户 (伪代码) $user = UserModel::where('username', $username)->find(); if (!$user || !password_verify($password, $user->password)) { return $this->error('用户名或密码错误'); } // 2. 生成JWT Payload $payload = [ 'iss' => 'your-issuer', // 签发者 'iat' => time(), // 签发时间 'exp' => time() + 7200, // 过期时间(2小时) 'uid' => $user->id, // 自定义信息:用户ID ]; // 3. 使用密钥生成Token $token = JWT::encode($payload, config('jwt.key'), 'HS256'); // 4. 返回给客户端 return $this->success(['token' => $token, 'user_info' => $user]); } -
ThinkPHP 中间件验证 JWT:
php
<?php namespace app\api\middleware; use Firebase\JWT\JWT; use think\Response; class AuthMiddleware { public function handle($request, \Closure $next) { $token = $request->header('Authorization'); if (!$token) { return Response::create(['code' => 401, 'msg' => 'Token不存在'], 'json'); } try { $decoded = JWT::decode($token, config('jwt.key'), ['HS256']); // 将解码出的用户信息存入请求,方便后续控制器使用 $request->uid = $decoded->uid; } catch (\Exception $e) { return Response::create(['code' => 401, 'msg' => 'Token无效或已过期'], 'json'); } return $next($request); } }
3. 商品模块
-
uni-app 端: 使用
swiper组件做轮播图,scroll-view做分类筛选,v-for渲染商品列表。上拉加载更多通过onReachBottom生命周期实现。 -
ThinkPHP 端: 商品列表接口需要支持分页、分类筛选、排序、关键词搜索。
php
public function productList() { $page = input('page', 1); $size = input('size', 10); $categoryId = input('category_id'); $keyword = input('keyword'); $order = input('order', 'sales_desc'); // 默认按销量降序 // 构建查询条件 $model = ProductModel::where('status', 1); // 上架商品 if ($categoryId) { $model->where('category_id', $categoryId); } if ($keyword) { $model->whereLike('name', "%{$keyword}%"); } // 排序逻辑 switch ($order) { case 'price_asc': $model->order('price asc'); break; case 'price_desc': $model->order('price desc'); break; default: $model->order('sales desc'); } // 分页查询 $list = $model->paginate(['page' => $page, 'list_rows' => $size]); return $this->success($list); }
4. 购物车模块
- uni-app 端: 购物车数据可以同时存储在 Vuex (内存,保证多页面同步) 和 本地存储 (uni.setStorage, 防止刷新丢失) 中。
- ThinkPHP 端: 提供添加、删除、修改数量、获取列表的接口。核心表:
cart(id, user_id, product_id, num, selected)。
5. 订单与支付模块 (核心)
-
下单流程:
- uni-app 提交商品和收货信息。
- ThinkPHP 创建订单(生成唯一订单号、校验库存、计算总价)、预扣库存(防止超卖)。
- 调用微信/支付宝统一支付接口,获取支付参数(如微信的
timeStamp,nonceStr,package,signType,paySign)。 - 返回支付参数给 uni-app。
- uni-app 调用
uni.requestPayment()发起客户端支付。
-
支付回调:
- 支付成功后,微信/支付宝服务器会异步通知 ThinkPHP 提供的回调接口。
- 此接口需验证签名、更新订单状态为已支付、真实扣减库存、记录流水等。
- 重要: 回调接口内逻辑必须做幂等性处理(防止重复通知导致重复更新)。
四、全渠道适配要点
-
条件编译: uni-app 的最大优势。
javascript
// #ifdef H5 console.log('这是在H5平台上'); // #endif // #ifdef MP-WEIXIN console.log('这是在微信小程序平台上'); // #endif // #ifdef APP console.log('这是在App平台上'); // #endif -
支付对接:
- H5: 通常使用微信H5支付或支付宝网页支付。
- 微信小程序: 必须使用小程序支付,调用
uni.requestPayment(OBJECT)传入微信返回的参数。 - App: 使用App支付,同样使用
uni.requestPayment,但需要配置各自的支付SDK。
-
登录授权:
- 微信小程序: 使用
uni.login()获取code,传给后端,后端用code换openid和session_key完成 unionid 体系下的登录。 - H5/App: 使用传统的账号密码登录或手机号验证码登录。
- 微信小程序: 使用
五、性能与优化建议
-
API 优化: ThinkPHP 接口使用 Redis 缓存热点数据(如商品详情、首页数据)。
-
图片优化: 图片资源务必存放在 OSS/COS 上,并开启 CDN 加速。
-
数据库优化: 为高频查询字段建立索引(如
product表的category_id,status)。 -
uni-app 优化:
- 使用图片懒加载。
- 长列表使用虚拟列表(可通过
uv-ui等组件库实现)。 - 减少不必要的
setData操作。
总结
打造这样一个平台,本质上是将 ThinkPHP 的强大后端能力 与 uni-app 的跨端能力 完美结合。
- ThinkPHP 侧重点: 稳健的API设计、安全的业务逻辑、高效的数据库操作、第三方服务集成(支付、短信、OSS)。
- uni-app 侧重点: 优雅的页面实现、流畅的用户体验、跨端的平台适配、本地状态管理。
建议从一个小模块开始(如用户登录->商品列表->商品详情),逐步迭代开发,并持续进行跨端测试,最终构建出功能完备的全渠道电商平台。