uni-app 接微信支付的完整流程是什么?前端、后端、微信分别做什么?
本文默认语境是 uni-app 发起微信支付,支付渠道是 微信小程序 / 微信客户端生态。面试时要主动说明:不同终端的拉起方式会有差异,但核心链路都绕不开 3 个角色:前端下单请求、后端统一签名、客户端拉起支付、微信异步回调确认结果。
面试速答(30 秒版 TL;DR)
- 微信支付流程不能简单说成“前端调个支付 API 就行”,真正的完整链路是:
- 前端请求业务后端创建订单
- 后端调用微信统一下单接口,拿到支付参数
- 后端把签名后的支付参数返回前端
- 前端调用
uni.requestPayment拉起微信支付 - 用户完成支付后,微信通过回调通知后端
- 后端验签、更新订单状态,前端再主动查询最终结果
- 面试里最关键的一句是:
- 支付结果不能只信前端 success 回调,最终要以后端异步通知和订单查询为准。
心智模型:支付不是一个前端动作,而是一条“交易状态流”
很多人第一次接微信支付,会误以为流程是:
- 用户点支付
- 前端拉起收银台
- 返回成功
- 订单结束
这个理解太浅,因为支付本质上是一次交易状态流转。
这里至少有 4 个系统参与:
- 前端应用
- 业务后端
- 微信支付平台
- 用户客户端
这张图最重要的点不是步骤数量,而是你要看出:
- 前端只负责“发起支付”
- 后端负责“创建订单、签名、验签、改状态”
- 微信负责“真正扣款与通知”
1. 为什么微信支付必须后端参与,前端不能自己签
这是支付题里非常核心的安全点。
因为支付流程里会涉及:
- 商户号
- API 密钥 / 私钥
- 签名
- 金额与订单号校验
这些都不能放到前端。
所以面试里要明确说:
- 前端只能拿后端生成好的支付参数,不能自己直接和微信支付平台做敏感签名交互。
如果让前端自己签,会有明显风险:
- 密钥泄露
- 金额被篡改
- 订单号伪造
2. 一条完整的支付链路应该怎么讲
2.1 前端先请求业务后端创建订单
用户点击“立即支付”后,前端不是直接调支付,而是先调用业务接口,例如:
const res = await uni.request({
url: '/api/pay/create-order',
method: 'POST',
data: {
skuId: 'sku_1001',
count: 2,
addressId: 'addr_99',
},
})
这一步业务后端通常要做:
- 校验商品和库存
- 计算最终金额
- 创建业务订单
- 把订单状态置为“待支付”
注意这里有一个高频面试点:
- 支付金额应以后端计算为准,不能信前端传的金额。
2.2 后端调用微信下单接口,拿支付参数
业务后端创建完订单后,再去调微信支付相关接口,生成预支付信息。
这一步后端通常要完成:
- 生成商户订单号
- 组装支付请求参数
- 做签名
- 调微信接口
- 获取
prepay_id或对应支付参数
然后再把前端调用支付所需字段返回给客户端。
2.3 前端调用 uni.requestPayment
这是 uni-app 侧最核心的支付 API。
示例:
async function pay(orderId: string) {
const { data } = await uni.request({
url: '/api/pay/prepare',
method: 'POST',
data: { orderId },
})
const payInfo = data.data
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: 'wxpay',
timeStamp: payInfo.timeStamp,
nonceStr: payInfo.nonceStr,
package: payInfo.package,
signType: payInfo.signType,
paySign: payInfo.paySign,
success(res) {
resolve(res)
},
fail(err) {
reject(err)
},
})
})
}
这里要特别强调:
uni.requestPayment的参数不是前端自己拼的- 它们应当全部来自后端
2.4 支付结果要以后端异步通知为准
前端调用 uni.requestPayment 后,即使进入了 success 回调,也不能立刻把订单强行标记成“支付成功”。
原因是:
- 前端回调只说明客户端侧支付流程走到了某个阶段
- 真正可靠的交易确认,必须以后端收到微信异步通知并验签成功为准
这是支付题的关键结论。
你可以直接背这句话:
- 前端 success 只能说明“支付发起结果看起来成功”,不能单独作为最终到账依据。
3. 为什么支付结果要“前端查询 + 后端回调”双保险
因为支付链路很容易出现时序问题。
例如:
- 用户付完钱,前端页面被关闭
- 微信已经回调后端,但前端还没拿到结果
- 前端拿到
fail,但实际上用户已完成支付 - 网络抖动导致回调和前端跳转顺序错乱
所以常见工程做法是:
3.1 后端异步通知负责改订单最终状态
后端收到微信通知后:
- 验签
- 校验金额、商户订单号、支付状态
- 幂等更新订单
- 记录支付流水
3.2 前端在支付返回页主动轮询或查询订单状态
例如:
const { data } = await uni.request({
url: '/api/pay/query-order-status',
method: 'GET',
data: { orderId },
})
if (data.data.status === 'PAID') {
uni.redirectTo({
url: `/pages/pay/result?orderId=${orderId}`,
})
}
这样做的价值是:
- 前后端状态更容易收敛
- 用户看到的是业务订单最终状态,而不是单次前端回调结果
4. 面试里最容易被追问的几个安全与一致性问题
4.1 为什么金额必须后端计算
因为前端参数可以篡改。
如果金额由前端提交并直接信任,就可能出现:
- 1 分钱买到 100 元商品
- 修改商品数量或优惠金额
所以金额、优惠、运费、最终应付,都要由后端重新计算并落库。
4.2 为什么异步通知要验签
因为后端不能无条件相信任何外部请求。
验签的作用是确认:
- 这个通知确实来自微信
- 内容没有被篡改
4.3 为什么更新订单要做幂等
因为支付通知可能重复到达,或者前端重复请求查询与补偿。
如果没有幂等控制,可能出现:
- 重复发货
- 重复加积分
- 重复记账
所以后端更新支付成功状态时,要按订单号或支付流水号做幂等保护。
5. 典型题 & 标准答法
Q1:uni-app 接微信支付的流程是什么?
标准答法:
- 前端调用业务接口创建待支付订单
- 后端按订单信息调用微信统一下单接口,拿到预支付参数并签名
- 后端把支付参数返回前端
- 前端调用
uni.requestPayment - 微信支付完成后,微信异步通知后端
- 后端验签、校验金额并幂等更新订单状态
- 前端再查询订单状态并展示最终结果
Q2:为什么不能只看 uni.requestPayment 的 success?
- 因为前端 success 不是最终入账证明
- 最终支付结果应以后端异步通知和订单查询结果为准
Q3:支付链路里前端和后端分别负责什么?
- 前端:发起支付、展示支付中状态、查询结果页
- 后端:创建订单、调微信下单、签名、验签、更新状态、幂等处理
6. 常见追问
6.1 用户支付中途取消怎么办?
前端通常会进入 fail 或取消分支,但业务上不能立刻认定订单彻底失败。
更稳的做法是:
- 订单先保持待支付
- 提示用户可继续支付
- 以后端查询或超时关闭策略为准
6.2 为什么要有“待支付”“支付中”“支付成功”“已关闭”这些状态?
因为支付不是瞬时动作,而是状态机。
状态拆清楚后,系统才好处理:
- 超时未支付关闭
- 回调迟到
- 用户重复进入支付页
- 支付成功后的发货 / 积分 / 通知
6.3 支付成功页为什么有时会“先失败后成功”?
因为前端回调、后端通知、订单查询三者可能不同步。
所以正确做法不是只看一次前端回调,而是:
- 展示“支付结果确认中”
- 主动查询订单状态
- 以后端最终状态为准
7. 易错点 / 坑
- 前端直接信任支付 success,立刻把订单记成功
- 金额由前端传入且后端未复算
- 后端收到支付通知不验签
- 订单状态更新没有幂等控制
- 用户取消支付后直接把订单永久关闭,导致补支付链路混乱
- 没有支付结果查询页,只依赖一次性回调
速记要点
- 支付流程 = 前端发起 + 后端签名 + 微信扣款 + 后端回调确认
uni.requestPayment只是拉起支付,不等于最终成功- 最终状态以后端异步通知和查询为准
- 金额必须后端计算
- 回调必须验签
- 更新订单必须幂等