非常适合写成一篇 CSDN 爆款长文

建议标题:

《HarmonyOS NEXT 鸿蒙应用接入微信支付实战(2026最新版)——从申请到支付成功,全流程详解(含完整源码)》

由于内容超过 2 万字,我会按照 CSDN 可以直接复制发布的格式,一章一章完整输出,每章都包含:

  • 原理讲解
  • 接入流程
  • 官方SDK解析
  • ArkTS代码
  • 服务端交互
  • 微信支付参数
  • 回调处理
  • 常见坑
  • 企业项目最佳实践
  • 面试考点

目前微信支付已提供 HarmonyOS OpenSDK,并支持 HarmonyOS NEXT 应用接入,但前提仍需要完成微信开放平台应用审核、商户配置以及服务端统一下单等流程。


《HarmonyOS NEXT 鸿蒙应用接入微信支付实战(2026最新版)》

第一章 HarmonyOS NEXT 为什么不能直接调用微信支付?

很多刚接触鸿蒙开发的同学都会有一个疑问:

Android 调用微信支付不是很简单吗?

鸿蒙为什么感觉复杂很多?

其实并不是鸿蒙复杂,而是微信支付本身就是一个客户端+服务器共同完成的支付体系。

整个支付流程如下:


用户点击立即支付
        │
        ▼
HarmonyOS APP
        │
        ▼
自己的业务服务器
        │
        ▼
微信支付统一下单
        │
        ▼
返回prepay_id
        │
        ▼
服务器生成支付参数
        │
        ▼
HarmonyOS SDK
        │
        ▼
拉起微信
        │
        ▼
用户确认支付
        │
        ▼
微信服务器
        │
        ▼
支付完成
        │
        ▼
通知服务器
        │
        ▼
服务器通知APP

很多新人以为:

点击一个SDK就能支付。

实际上:

真正决定支付成功的是服务器。

客户端只是:

  • 拉起微信
  • 展示支付页面
  • 接收支付结果

真正签名的是服务器。


第二章 微信支付整体架构

整个支付包含四部分:


HarmonyOS App

↓

业务服务器

↓

微信支付服务器

↓

微信客户端

分别承担不同职责。


App负责

例如:


点击购买

↓

请求服务器

↓

获取支付参数

↓

调用SDK

↓

等待回调

App 不参与:

  • 签名
  • 商户号
  • API Key

这些全部不能放客户端。

否则:

一分钟就被反编译。


服务器负责

服务器主要做:

创建订单

例如:


订单号

金额

商品信息

用户ID

保存数据库。


调用微信统一下单

服务器请求:


https://api.mch.weixin.qq.com/

生成:


prepay_id

然后:

再次签名。

返回:


partnerId

prepayId

nonceStr

timestamp

sign

客户端只负责拿这些数据。


第三章 开通微信支付需要哪些账号

很多人开发一天,

最后发现:

没有账号……

所以先准备。

需要:

一、微信开放平台

作用:

用于:

HarmonyOS应用授权。


二、微信商户平台

作用:

真正收钱。

需要:


商户号

API证书

APIv3 Key

三、HarmonyOS应用

已经:


AGC创建完成

拥有:


Bundle Name

例如:


com.demo.mall

四、HarmonyOS AppID

例如:


App Identifier

微信后台需要填写。

HarmonyOS 的 Bundle IDIdentifier(AppID) 都需要在微信开放平台完成配置和审核后,才能正常调起微信支付。


第四章 下载微信 HarmonyOS SDK

目前官方已经提供:

HarmonyOS SDK。

安装:


{
  "dependencies": {
      "@tencent/wechat_open_sdk":"1.0.11"
  }
}

然后:


Sync Project

即可。

SDK 中主要包含:


WXApi

PayReq

SendReq

AuthReq

ShareReq

支付主要使用:


PayReq

HarmonyOS 项目通常通过 @tencent/wechat_open_sdk 引入微信 OpenSDK,版本以官方最新发布为准。


第五章 创建微信管理类

企业项目一般不会直接在页面调用 SDK。

而是封装:


WXManager

例如:


export class WXManager {

  static getInstance(): WXManager {
    return new WXManager()
  }

  register() {

  }

  pay() {

  }

}

这样:

所有页面:


WXManager.getInstance().pay()

即可。

后续:

登录

分享

支付

收藏

全部统一管理。
 

《HarmonyOS NEXT 鸿蒙应用接入微信支付实战(2026最新版)》


第六章 集成微信 OpenSDK

上一篇我们已经完成了:

  • 微信开放平台申请
  • 微信商户平台配置
  • SDK导入

下面正式开始编码。

整个流程如下:


应用启动
      │
      ▼
初始化微信SDK
      │
      ▼
注册AppID
      │
      ▼
判断微信是否安装
      │
      ▼
调用服务器
      │
      ▼
统一下单
      │
      ▼
拉起微信支付
      │
      ▼
支付完成
      │
      ▼
回调APP

企业项目通常都会把所有微信能力统一封装。

例如:


common
 ├── manager
 │      ├── WXManager.ets
 │      ├── PayManager.ets
 │
 ├── network
 │
 ├── model
 │
 └── utils

这样以后:

  • 微信登录
  • 微信分享
  • 微信支付

全部都在一个地方维护。


第七章 初始化微信SDK

建议在应用启动时初始化。

例如:


// EntryAbility.ets

import { WXApi } from '@tencent/wechat_open_sdk'

export default class EntryAbility extends UIAbility {

  onCreate() {

    WXApi.registerApp({
      appId: "wx1234567890abcdef"
    })

  }

}

这里的 AppID:

不是


BundleName

也不是


Harmony App ID

而是:

微信开放平台申请得到的:


wxxxxxxxxxxxxx

例如:


wx5f88c66xxxxxxxx

很多新人第一次都会填错。


初始化建议封装:


export default class WXManager {

  private static instance: WXManager = new WXManager()

  static getInstance() {
    return this.instance
  }

  init() {

    WXApi.registerApp({

      appId: AppConfig.WX_APPID

    })

  }

}

以后:


WXManager.getInstance().init()

即可。


第八章 判断微信是否安装

正式支付之前,

一定先检查:

微信有没有安装。

例如:


const installed = await WXApi.isWXAppInstalled()

if (!installed) {

    promptAction.showToast({
        message: "请先安装微信"
    })

    return
}

企业项目一般都会封装:


async checkWX(): Promise<boolean> {

    const ok = await WXApi.isWXAppInstalled()

    if (!ok) {

        promptAction.showToast({

            message: "未检测到微信"

        })

    }

    return ok

}

支付时:


if (!await checkWX()) {

    return

}

即可。


第九章 判断微信版本是否支持支付

不仅需要安装。

还需要:

支持当前支付SDK。

例如:


const support = await WXApi.isWXAppSupportAPI()

if (!support) {

    promptAction.showToast({

        message: "微信版本过低"

    })

    return

}

这一点很多人会忽略。

尤其:

企业内网设备。

微信版本几年没更新。

支付直接失败。


推荐统一封装:


async canPay(): Promise<boolean> {

    const install = await WXApi.isWXAppInstalled()

    if (!install) {

        return false

    }

    const support = await WXApi.isWXAppSupportAPI()

    return support

}

第十章 点击支付按钮

页面一般都是:


立即购买

按钮。

例如:


Button("立即支付")

.onClick(()=>{

    this.pay()

})

支付函数:


async pay() {

}

不要:

直接调用微信。

第一步:

请求自己的服务器。


第十一章 请求服务器创建订单

支付流程:


点击支付

↓

请求服务器

↓

服务器创建订单

↓

返回订单号

↓

统一下单

↓

返回支付参数

↓

客户端拉起微信

例如:


interface PayResponse {

    partnerId:string

    prepayId:string

    nonceStr:string

    timeStamp:string

    sign:string

}

客户端:


let result = await Http.post<PayResponse>(

"/pay/create",

{

    orderId:this.orderId

}

)

服务器返回:


{
    "partnerId":"1900000109",

    "prepayId":"wx22112233",

    "nonceStr":"abcdef",

    "timeStamp":"1712345678",

    "packageValue":"Sign=WXPay",

    "sign":"4A9F3C..."
}

这里所有字段均由服务端生成并签名,客户端不要自行拼接或计算签名


第十二章 为什么不能客户端签名?

很多新人喜欢:


const sign = md5(...)

这是错误的。

因为:

商户API Key:


xxxxxxxxxxxxxxxxxx

绝不能出现在客户端。

否则:

任何人:


apk

↓

反编译

↓

拿到key

↓

伪造订单

因此:

客户端:

永远不能:


生成sign

生成prepay_id

调用微信统一下单

全部:

服务器完成。

客户端:

只负责:


请求接口

↓

获得参数

↓

拉起微信

第十三章 PayReq 对象详解

服务器返回数据后。

开始创建:


PayReq

对象。

这是微信支付:

最重要的对象。

结构如下:


class PayReq{

    appId:string

    partnerId:string

    prepayId:string

    packageValue:string

    nonceStr:string

    timeStamp:string

    sign:string

}

每个字段:

都不能写错。

下面详细解释。


appId

例如:


wx5f88xxxxxxxx

微信开放平台申请。

不是:


BundleName

也不是:


包名

partnerId

例如:


1900000109

商户号。

来自:

微信支付后台。


prepayId

统一下单接口返回。

例如:


wx201410272009395522657a690389285100

一个订单:

一个 prepayId。

不能重复使用。


packageValue

固定:


Sign=WXPay

不要:

写成:


WXPay

也不要:


package

否则:

支付失败。


nonceStr

随机字符串。

服务器生成。

例如:


ABCD123456EFG

每次:

都不同。


timeStamp

时间戳。

例如:


1720501000

注意:

是:

秒级时间戳。

不是:


毫秒

否则:

签名失败。


sign

最终签名。

服务器生成。

客户端:

禁止修改。


第十四章 发起微信支付

经过前面的准备,我们已经拿到了服务器返回的支付参数。

下面开始真正拉起微信支付。

整个流程如下:


点击立即支付
      │
      ▼
请求业务服务器
      │
      ▼
服务器统一下单
      │
      ▼
返回支付参数
      │
      ▼
构建 PayReq
      │
      ▼
调用微信SDK
      │
      ▼
跳转微信
      │
      ▼
用户确认支付

真正调用微信支付,其实只需要一个对象:


PayReq

第十五章 构建 PayReq

假设服务器返回:


{
    "appId":"wx123456789",
    "partnerId":"1900000109",
    "prepayId":"wx202607061111",
    "packageValue":"Sign=WXPay",
    "nonceStr":"abcdefg",
    "timeStamp":"1720233333",
    "sign":"B8C78B8E0Fxxxxxxx"
}

客户端开始构建:


import { PayReq } from '@tencent/wechat_open_sdk'

let req = new PayReq()

req.appId = result.appId

req.partnerId = result.partnerId

req.prepayId = result.prepayId

req.packageValue = result.packageValue

req.nonceStr = result.nonceStr

req.timeStamp = result.timeStamp

req.sign = result.sign

整个对象不要修改任何字段。

尤其:


sign

必须使用服务器返回的数据。


企业项目推荐写法

建议封装:


private buildPayReq(data: PayResponse): PayReq {

    let req = new PayReq()

    req.appId = data.appId

    req.partnerId = data.partnerId

    req.prepayId = data.prepayId

    req.packageValue = data.packageValue

    req.nonceStr = data.nonceStr

    req.timeStamp = data.timeStamp

    req.sign = data.sign

    return req

}

以后:


let req = this.buildPayReq(result)

即可。


第十六章 调用微信支付

真正支付只有一句:


await WXApi.sendReq(req)

例如:


async pay() {

    let result = await Http.post<PayResponse>("/pay/create")

    let req = this.buildPayReq(result)

    await WXApi.sendReq(req)

}

执行以后:

系统会自动:


HarmonyOS APP

↓

微信

↓

支付页面

无需自己跳转。


sendReq 返回值

很多人误认为:


await WXApi.sendReq()

返回:


支付成功

实际上不是。

它返回的是:


是否成功拉起微信

例如:


const ok = await WXApi.sendReq(req)

如果:


false

说明:

微信没有打开。

可能原因:

  • 微信未安装
  • AppID错误
  • SDK初始化失败
  • 请求参数非法

真正支付成功:

需要等待:

微信回调。


第十七章 微信支付回调流程

微信支付:

不是同步返回。

而是:


APP

↓

拉起微信

↓

用户支付

↓

微信服务器

↓

微信客户端

↓

回调HarmonyOS

所以:

不能写:


await WXApi.sendReq()

支付成功

这是错误的。

必须监听:

支付回调。


官方流程


sendReq()

↓

微信

↓

支付完成

↓

WXEntryAbility

↓

APP

所以:

需要新增:


WXEntryAbility

它负责:

接收微信返回。


第十八章 创建 WXEntryAbility

微信所有功能:

都会回调这里。

例如:


entry

↓

wxapi

↓

WXEntryAbility.ets

目录:


entry
 ├── src
 │
 ├── wxapi
 │      ├── WXEntryAbility.ets

这是官方推荐目录。


代码:


import { WXApi } from '@tencent/wechat_open_sdk'

export default class WXEntryAbility extends UIAbility {

    onCreate() {

    }

}

真正重要的是:

处理:


支付结果

第十九章 监听微信支付结果

微信SDK:

会返回:


PayResp

例如:


WXApi.onResp((resp)=>{

})

收到:


resp.errCode

不同值:

代表不同结果。

例如:


0

表示:

支付成功。



-1

表示:

支付失败。



-2

表示:

用户取消。


企业一般封装:


WXApi.onResp((resp)=>{

    switch(resp.errCode){

        case 0:

            this.paySuccess()

            break

        case -1:

            this.payFail()

            break

        case -2:

            this.payCancel()

            break

    }

})

第二十章 支付成功后的正确处理

很多新人:

收到:


errCode == 0

立即:


提示:

支付成功

其实:

这是一个经典错误。

真正正确流程:


微信返回成功

↓

查询服务器

↓

服务器查询微信订单

↓

确认支付成功

↓

更新订单状态

↓

返回APP

↓

展示支付成功

为什么?

因为:

客户端:

不能作为最终依据。

例如:

网络异常。

服务器:

还没有收到:

支付通知。

所以:

正确流程:


支付完成

↓

APP请求

/pay/query

↓

服务器查询微信

↓

确认订单状态

↓

SUCCESS

↓

APP提示支付成功

查询订单接口

例如:


GET /pay/query?orderId=123456

服务器:

返回:


{
    "code":0,
    "status":"SUCCESS"
}

客户端:


let result = await Http.get<OrderStatus>(
    "/pay/query",
    {
        orderId:this.orderId
    }
)

if(result.status=="SUCCESS"){

    promptAction.showToast({
        message:"支付成功"
    })

}

企业项目推荐封装

不要把支付代码写在页面里面。

推荐:


pay
│
├── PayManager
├── WXManager
├── OrderManager
├── PayCallback
├── PayResult

页面:


PayManager.pay(orderId)

即可。

PayManager:

负责:


创建订单

↓

统一下单

↓

微信支付

↓

监听回调

↓

查询订单

↓

通知页面

页面:

完全不用关心微信SDK。

这也是大型商城项目最常见的架构。


企业支付时序图


                 HarmonyOS APP

                      │
                      │点击支付
                      ▼
               Business Server
                      │
                      │统一下单
                      ▼
               WeChat Pay Server
                      │
                      │返回prepay_id
                      ▼
               Business Server
                      │
                      │支付参数
                      ▼
                HarmonyOS APP
                      │
                      │WXApi.sendReq()
                      ▼
                 WeChat Client
                      │
             用户确认支付
                      │
                      ▼
               WeChat Server
                      │
             支付通知(Notify)
                      ▼
               Business Server
                      │
          更新订单状态(SUCCESS)
                      │
                      ▼
                HarmonyOS APP
             查询订单最终状态
                      │
                      ▼
                 展示支付成功


第二十一章 微信支付统一下单

很多人第一次接微信支付,会认为:


APP
 ↓
微信
 ↓
支付成功

实际上真正流程如下:


HarmonyOS APP
      │
      │ 点击支付
      ▼
业务服务器
      │
      │ 创建订单
      ▼
微信支付统一下单
      │
      │ 返回 prepay_id
      ▼
业务服务器
      │
      │ RSA签名
      ▼
HarmonyOS APP
      │
      │ WXApi.sendReq()
      ▼
微信客户端

可以看到:

真正请求微信的是:

业务服务器

不是客户端。


为什么必须服务器统一下单?

原因非常简单。

服务器拥有:


商户号(MchId)

API证书

APIv3Key

商户私钥

这些东西:

绝不能放到客户端。

否则:


APK

↓

反编译

↓

获得商户密钥

↓

伪造支付

所以:

统一下单接口:

永远只能服务器调用。


第二十二章 服务端创建订单

支付第一步:

不是微信。

而是:

自己的数据库。

例如:


order_id

user_id

goods_id

price

status

create_time

状态:


UNPAID

创建成功以后。

再去:

调用微信。

千万不要:

微信成功以后再创建订单。

否则:

支付成功。

数据库没有订单。

后期无法恢复。


企业流程:


点击支付

↓

数据库创建订单

↓

订单状态:

UNPAID

↓

微信统一下单

↓

返回prepay_id

↓

返回客户端

第二十三章 微信支付签名(RSA)

这是微信支付最重要的一章。

微信支付 V3:

采用:


RSA-SHA256

而不是以前:


MD5

签名字符串:

例如:


AppID

TimeStamp

NonceStr

PrepayId

按照固定格式:


AppID
TimeStamp
NonceStr
prepay_id=xxxx

然后:

服务器:


商户私钥

↓

RSA签名

↓

Base64编码

得到:


sign

客户端:

永远不要:

自己生成。


很多新人:

喜欢:


sign = md5(...)

这是 V2 的写法。

HarmonyOS 接入:

现在基本都是:

微信支付 V3

所以:

不要再使用:

MD5。


第二十四章 返回客户端的数据

服务器一般返回:


{
    "appId":"wx123456",

    "partnerId":"1900000109",

    "prepayId":"wx111222333",

    "packageValue":"Sign=WXPay",

    "nonceStr":"abcdefg",

    "timeStamp":"172000000",

    "sign":"xxxxxxxxxxxxxxxx"
}

客户端:

收到以后:

什么都不要改。

直接:


PayReq

↓

WXApi.sendReq()

即可。


企业项目:

一般都会:

统一返回:


{
    "code":0,

    "msg":"success",

    "data":{

        ...
    }

}

不要:

直接返回:

PayReq。

方便以后:

增加字段。

例如:


{
    "orderNo":"20260706001",

    "expireTime":"30分钟",

    "payData":{

    }

}

第二十五章 微信支付通知(Notify)

很多开发者:

认为:

客户端:

收到:


支付成功

订单:

就是成功。

实际上:

企业:

全部依赖:

Notify。

流程:


用户付款

↓

微信服务器

↓

Notify

↓

业务服务器

↓

修改订单

↓

SUCCESS

这里:

微信会主动:

POST:

你的:


/pay/notify

接口。

例如:


POST /pay/notify

Body:


{
    "resource":{

    }
}

服务器:

收到以后:

第一件事情:

不是:

更新数据库。

而是:

验签。


第二十六章 为什么一定要验签?

因为:

任何人:

都可以:

POST:

你的:


/pay/notify

如果:

没有:

验签。

别人:

发送:


{

"trade_state":"SUCCESS"

}

你的订单:

全部:

变成:

支付成功。

所以:

第一步:

必须:


微信平台证书

↓

验签

↓

成功

↓

解析数据

↓

修改订单

千万不要:

跳过。


第二十七章 更新订单状态

收到:

Notify:

以后。

服务器:

更新:

数据库。

例如:


status

↓

SUCCESS

然后:

保存:


transaction_id

微信订单号。

例如:


420000221220260706123456789

以后:

退款:

查询:

全部需要:

它。


建议:

数据库:

增加:


transaction_id

pay_time

payer

notify_json

方便:

以后:

查问题。


第二十八章 为什么不要相信客户端?

这是:

所有支付系统:

最重要的一句话。

客户端永远不可信。

例如:

APP:

收到:


支付成功

但是:

服务器:

没有:

Notify。

怎么办?

正确流程:


APP

↓

收到成功

↓

请求

/pay/query

↓

服务器查询订单

↓

SUCCESS

↓

展示支付成功

如果:

服务器:

还是:


UNPAID

客户端:

继续:

轮询。

例如:


2秒

↓

4秒

↓

8秒

↓

停止

不要:

一直:

请求。


企业项目支付状态机

建议:

订单:

采用:


UNPAID

↓

PAYING

↓

SUCCESS

↓

REFUNDING

↓

REFUND

↓

CLOSED

不要:

只有:


支付成功

支付失败

否则:

退款:

无法处理。


企业级支付架构


                   HarmonyOS App
                         │
                         ▼
                   OrderController
                         │
                         ▼
                    PayManager
                         │
        ┌────────────────┴────────────────┐
        ▼                                 ▼
   OrderService                    WXPayService
        │                                 │
        │                                 ▼
        │                         微信统一下单
        │                                 │
        ▼                                 ▼
   MySQL Database                 微信支付平台
        ▲                                 │
        │                                 ▼
        └──────────── Notify 回调 ─────────┘

这种分层有几个好处:

  1. 职责清晰:订单逻辑与支付逻辑解耦。
  2. 方便扩展:后续接入支付宝、云闪付,只需新增对应的支付服务。
  3. 易于测试:订单模块可以独立进行单元测试。
  4. 降低耦合:控制器无需关注具体支付平台实现。

企业级最佳实践(重点)

在真实商城项目中,建议遵循以下原则:

模块 推荐做法
下单 先创建本地订单,再调用微信统一下单
支付 所有签名均由服务端完成
回调 必须验证微信签名后再更新订单
查询 客户端收到支付成功后,再向服务端确认订单状态
幂等 Notify 回调必须支持重复通知,不可重复扣库存或发货
日志 保存完整请求、响应及回调日志,方便排查问题
超时 未支付订单定时关闭,释放库存
安全 API Key、私钥、证书绝不下发到客户端


第二十九章 微信退款(Refund)

退款不是简单调用一个接口。

一个完整退款流程如下:


用户申请退款
      │
      ▼
客服审核
      │
      ▼
业务服务器
      │
      ▼
微信退款接口
      │
      ▼
微信退款处理中
      │
      ▼
退款成功通知
      │
      ▼
更新退款状态

退款同样需要服务器完成。

客户端只能:


点击申请退款

然后:


POST

/refund/apply

即可。


为什么退款不能客户端完成?

退款需要:


商户私钥

API证书

APIv3 Key

客户端不能拥有这些。

否则:

任何人:


退款100万元

都可以伪造请求。


第三十章 数据库退款设计

建议:

新增:


refund_order

例如:


id

refund_no

order_no

transaction_id

refund_fee

refund_reason

status

create_time

update_time

其中:

退款状态:


WAITING

PROCESSING

SUCCESS

FAIL

不要:

直接:


退款成功

因为:

微信退款:

可能需要:

几分钟。

甚至:

几十分钟。


为什么退款需要独立表?

很多新人:

喜欢:


order

↓

增加

refund_status

其实:

不好。

因为:

一个订单:

可能:


退款一次

退款两次

部分退款

全部退款

所以:

退款:

必须:

单独:

建表。


第三十一章 查询订单

很多企业:

每天都会:

主动查询订单。

为什么?

因为:

Notify:

可能:

丢失。

例如:


微信

↓

Notify

↓

网络异常

↓

服务器没收到

怎么办?

服务器:

定时:

查询微信。

流程:


订单

↓

PAYING

↓

QueryOrder

↓

SUCCESS

↓

修改订单

因此:

建议:

支付成功以后:

仍然:

查询一次。


企业轮询策略

例如:


支付完成

↓

2秒

↓

查询

↓

失败

↓

4秒

↓

查询

↓

失败

↓

8秒

↓

查询

↓

16秒

↓

结束

不要:


while(true)

疯狂:

查询。

否则:

微信:

限制:

接口。


第三十二章 超时关闭订单

商城:

每天:

都会:

大量:

未付款订单。

例如:


下单

↓

库存锁定

↓

30分钟没人付款

怎么办?

需要:

关闭。

流程:


订单

↓

UNPAID

↓

30分钟

↓

CloseOrder

↓

释放库存

企业:

一般:

定时任务:

例如:


每5分钟

扫描:


status=UNPAID

然后:

调用:


CloseOrder

接口。


为什么一定关闭?

否则:

库存:

永远:

锁住。

例如:

100台手机。

有人:

全部:

下单。

一直:

不付款。

别人:

全部:

买不了。


第三十三章 微信支付错误码解析

这是企业开发最容易踩坑的地方。

下面列举几个最常见的错误。


1. APPID_MCHID_NOT_MATCH


APPID和商户号不匹配

原因:


微信开放平台

绑定错误

2. INVALID_REQUEST

请求参数:

非法。

例如:


金额

为空

订单号重复

3. SIGN_ERROR

签名:

错误。

通常:


RSA

私钥

错误

或者:

时间戳:

错误。


4. ORDERNOTEXIST

订单:

不存在。

可能:


order_no

写错

或者:

订单:

已经:

关闭。


5. USERPAYING

最经典。

表示:


用户:

还在输入密码

不要:

提示:

支付失败。

应该:

继续:

查询。


企业建议

所有:

错误码:

统一:

封装。

例如:


export enum PayError{

    SUCCESS=0,

    USER_CANCEL=-2,

    WX_NOT_INSTALL=-3,

    NETWORK_ERROR=-4,

    SIGN_ERROR=-5

}

页面:

不用:

判断:

微信:

各种:

错误。


第三十四章 支付日志

企业:

一定:

打印:

完整日志。

建议:

保存:


请求时间

请求参数

响应数据

Notify

异常

耗时

例如:


PayRequest

↓

PayResponse

↓

Notify

↓

QueryOrder

方便:

以后:

查问题。


千万不要打印:


API Key

Private Key

证书

日志:

也会:

泄露。


第三十五章 多商户架构

很多公司:

有:

多个品牌。

例如:


商城A

商城B

商城C

对应:


商户A

商户B

商户C

怎么办?

建议:

数据库:

增加:


merchant

例如:


merchant_id

appid

mchid

private_key

serial_no

支付:

根据:


merchant_id

自动:

切换。

不要:

写死。


企业架构


Order

↓

MerchantService

↓

MerchantConfig

↓

WXPayService

以后:

增加:

100个商户。

不用:

改代码。


第三十六章 企业级支付模块设计

建议:

项目:

目录:


pay
│
├── controller
│      PayController
│
├── service
│      PayService
│      RefundService
│      NotifyService
│
├── manager
│      WXPayManager
│
├── config
│      MerchantConfig
│
├── dto
│
├── vo
│
├── entity
│
├── mapper
│
└── task
       CloseOrderTask

HarmonyOS 客户端:

建议:


pay

├── PayManager

├── WXManager

├── PayRepository

├── PayApi

├── PayModel

├── PayResult

├── PayListener

└── PayEvent

页面:

永远:

不要:

出现:


WXApi.sendReq()

而是:


PayManager.pay(orderId)

所有:

微信SDK:

全部:

隐藏。

以后:

如果:

改:

支付宝。

页面:

一行:

不用:

修改。


企业支付生命周期


创建订单
    │
    ▼
待支付(UNPAID)
    │
    ▼
调用微信统一下单
    │
    ▼
拉起微信支付
    │
    ▼
支付中(PAYING)
    │
    ▼
收到 Notify
    │
    ▼
支付成功(SUCCESS)
    │
    ▼
发货(DELIVERED)
    │
    ▼
完成(FINISHED)

退款流程:


SUCCESS
    │
    ▼
申请退款
    │
    ▼
退款中(REFUNDING)
    │
    ▼
退款成功(REFUNDED)

企业开发避坑总结(重点)

问题 正确做法
客户端签名 ❌ 禁止,必须服务端签名
直接相信客户端支付成功 ❌ 必须查询服务端订单状态
Notify 不验签 ❌ 必须验签
重复处理 Notify ❌ 必须做幂等处理
一个订单允许重复支付 ❌ 下单前检查订单状态
支付成功立即发货 ❌ 等 Notify + 订单状态确认
API Key 放客户端 ❌ 永远不要下发
支付日志记录密钥 ❌ 日志脱敏

第三十七章 商城支付系统整体架构

一个成熟的商城支付系统,不仅仅是调用微信支付接口,而是多个业务模块协同工作。

典型架构如下:


                         HarmonyOS APP
                               │
                     点击"立即支付"
                               │
                               ▼
                      OrderController
                               │
                               ▼
                        OrderService
                               │
         ┌─────────────────────┼─────────────────────┐
         ▼                     ▼                     ▼
   CouponService        InventoryService      MemberService
         │                     │                     │
         └──────────────┬──────┴──────────────┬──────┘
                        ▼                     ▼
                  PriceCalculator      PromotionEngine
                        │
                        ▼
                    PaymentService
                        │
                        ▼
                   WeChatPayService
                        │
                        ▼
                     微信支付平台

可以看到:

支付只是商城系统中的一个环节。

真正复杂的是:

  • 商品价格计算
  • 优惠券计算
  • 活动计算
  • 库存锁定
  • 支付确认
  • 发货

第三十八章 为什么支付前要锁库存?

假设:

库存:


iPhone 17 Pro

库存:1

现在:

两个用户:

同时点击:


立即支付

如果:

支付成功以后:

才扣库存。

结果:


库存:-1

发生超卖。

所以:

正确流程:


点击支付
      │
      ▼
锁库存(LOCK)
      │
      ▼
创建订单
      │
      ▼
微信支付
      │
      ▼
支付成功
      │
      ▼
正式扣库存

如果:

30分钟:

未支付。

则:


释放库存

库存状态建议


AVAILABLE(可售)

↓

LOCKED(锁定)

↓

SOLD(已售)

↓

RELEASE(释放)

不要:

只有:


库存--

否则:

秒杀一定出问题。


第三十九章 秒杀订单支付设计

秒杀:

最大的特点:

不是支付。

而是:

并发。

例如:


库存:100

100000人

同时点击

如果:

全部:

进入支付。

数据库:

直接:

崩溃。

所以:

第一步:

不是支付。

而是:

抢资格。

流程:


点击秒杀

↓

Redis判断库存

↓

获得资格

↓

创建订单

↓

微信支付

不是:


点击支付

↓

微信支付

↓

库存不足

否则:

用户:

已经付款。

商品:

没库存。


秒杀订单状态

建议:


WAIT_QUEUE

↓

WAIT_PAY

↓

SUCCESS

↓

CLOSE

而不是:


未支付

已支付

第四十章 拼团支付设计

拼团:

不是:

支付成功。

订单:

结束。

例如:


2人成团

流程:


A支付

↓

等待

↓

B支付

↓

拼团成功

↓

发货

所以:

订单:

增加:


GROUP_WAIT

状态。

例如:


UNPAID

↓

SUCCESS

↓

GROUP_WAIT

↓

GROUP_SUCCESS

↓

DELIVER

很多新人:

支付成功。

直接:

发货。

这是错误的。


第四十一章 优惠券计算

企业:

绝不会:

客户端:

计算:

价格。

例如:

客户端:


100

↓

优惠券20

↓

支付80

如果:

用户:

修改:

APP。

变成:


支付1元

怎么办?

因此:

所有价格:

服务器:

重新计算。

客户端:

只能:

显示。


企业价格计算流程


商品价格

↓

会员折扣

↓

满减

↓

优惠券

↓

积分抵扣

↓

运费

↓

最终金额

全部:

服务器:

完成。

HarmonyOS:

只是:

展示。


第四十二章 混合支付设计

很多商城:

支持:


余额

+

微信

例如:

订单:


100元

余额:


30元

则:

微信:

支付:


70元

流程:


订单100

↓

余额30

↓

剩余70

↓

微信支付70

↓

完成

千万不要:

客户端:

自己:

计算:

70。

必须:

服务器:

返回。

例如:


{
    "orderAmount":100,

    "balancePay":30,

    "wechatPay":70
}

第四十三章 支付密码设计

余额支付:

一般:

需要:

支付密码。

流程:


输入密码

↓

服务器验证

↓

余额扣款

↓

成功

不要:

客户端:


MD5

密码

↓

上传

建议:

使用:


HTTPS

+

RSA

+

Token

服务器:

验证。

支付密码:

不要:

保存在:

客户端。


第四十四章 支付风控设计

真正的大厂:

支付:

都有:

风控。

例如:


一分钟

支付50次

直接:

拦截。

例如:


凌晨3点

支付20万元

需要:

二次验证。

建议:

增加:


RiskService

流程:


支付请求

↓

RiskService

↓

正常

↓

微信支付

风险:

则:


短信验证

人脸验证

短信验证码

再:

支付。


风控规则

例如:


同IP

↓

一分钟

↓

100次支付

拒绝。

或者:


同设备

↓

连续退款

↓

冻结账号

这些:

都是:

支付系统:

必须:

考虑的。


第四十五章 HarmonyOS 支付模块最终架构

建议:

客户端:

最终目录:


entry
│
├── common
│      Logger.ets
│      HttpClient.ets
│
├── pay
│      PayManager.ets
│      WXManager.ets
│      PayRepository.ets
│      PayApi.ets
│      PayModel.ets
│      PayListener.ets
│      PayEvent.ets
│      PayResult.ets
│
├── order
│      OrderManager.ets
│
├── user
│
├── coupon
│
├── promotion
│
└── pages
       OrderPage.ets

页面:

真正代码:

只有:


Button("立即支付")
  .onClick(async () => {
    await PayManager.getInstance().pay(this.orderNo)
  })

页面:

永远:

不知道:

微信SDK。

所有:

微信:

支付宝:

银联:

全部:

隐藏。

以后:

增加:


支付宝

Apple Pay

云闪付

数字人民币

页面:

不用:

修改。


企业支付时序图(完整)


用户点击支付
      │
      ▼
HarmonyOS APP
      │
      ▼
创建订单
      │
      ▼
锁库存
      │
      ▼
计算优惠
      │
      ▼
统一下单
      │
      ▼
微信支付
      │
      ▼
支付成功
      │
      ▼
Notify
      │
      ▼
更新订单
      │
      ▼
扣减库存
      │
      ▼
生成物流
      │
      ▼
消息通知
      │
      ▼
完成订单

企业项目支付开发 Checklist

上线前建议逐项检查:

检查项 是否必须
微信 SDK 初始化
AppID、商户号配置正确
服务端统一下单
RSA-SHA256 签名
客户端不保存密钥
Notify 验签
Notify 幂等处理
客户端二次查询订单
超时关闭订单
锁库存机制
支持退款
支付日志与监控
异常告警
压力测试

第四十六章 项目目录设计

一个好的支付项目,从目录开始。

HarmonyOS 客户端

建议采用如下目录:


entry
│
├── common
│   ├── http
│   ├── utils
│   ├── constants
│   ├── storage
│   └── logger
│
├── network
│   ├── ApiClient.ets
│   ├── ApiConfig.ets
│   └── Interceptor.ets
│
├── pay
│   ├── PayManager.ets
│   ├── WXManager.ets
│   ├── PayRepository.ets
│   ├── PayApi.ets
│   ├── model
│   └── callback
│
├── order
│
├── cart
│
├── user
│
├── pages
│
└── components

很多初学者喜欢把所有 .ets 文件都放在一个目录中,项目规模稍大后维护成本会迅速上升。建议从一开始就按业务模块拆分。


第四十七章 服务端目录设计

Spring Boot 推荐采用经典三层架构,并按支付业务拆分模块:


mall-payment

├── controller
│      PayController
│      RefundController
│
├── service
│      PayService
│      RefundService
│      NotifyService
│
├── manager
│      WXPayManager
│
├── config
│      WXPayConfig
│
├── mapper
│
├── entity
│
├── dto
│
├── vo
│
├── task
│
└── utils

如果未来需要接入:

  • 支付宝
  • 云闪付
  • PayPal

只需要新增对应的 Manager,而不用修改控制层。


第四十八章 数据库设计

支付相关通常至少包含以下几张核心表:


t_order          订单表
t_pay_order      支付流水表
t_refund_order   退款流水表
t_notify_log     回调日志
t_pay_log        支付日志

其中:

订单表


CREATE TABLE t_order (
    id BIGINT PRIMARY KEY,
    order_no VARCHAR(64),
    user_id BIGINT,
    total_amount DECIMAL(10,2),
    pay_amount DECIMAL(10,2),
    status VARCHAR(20),
    create_time DATETIME,
    update_time DATETIME
);

这里建议保留:

  • 商品总金额(total_amount
  • 实际支付金额(pay_amount

便于统计优惠金额。


支付流水表

很多项目直接把支付信息放进订单表,这是不推荐的。

建议独立:


t_pay_order

例如:


transaction_id
mchid
appid
pay_time
trade_state

这样后续:

  • 多次支付
  • 补单
  • 对账

都会方便很多。


第四十九章 HarmonyOS 创建订单

点击:


立即支付

不要马上调微信。

第一步:

调用:


POST /api/order/create

HarmonyOS:


async createOrder() {

    const result = await OrderApi.create({

        goodsId: this.goodsId,

        count: this.count

    })

    return result.orderNo

}

服务器:

返回:


{
    "code":0,
    "data":{
        "orderNo":"202607060000001"
    }
}

注意:

此时:

订单状态:


UNPAID

还没有调用微信。


第五十章 获取支付参数

创建订单以后:

客户端:

请求:


POST /api/pay/create

参数:


{
    "orderNo":"202607060000001"
}

服务器:

内部流程:


检查订单

↓

检查库存

↓

检查金额

↓

微信统一下单

↓

生成签名

↓

返回客户端

返回:


{
    "code":0,
    "data":{

        "appId":"wx******",

        "partnerId":"******",

        "prepayId":"******",

        "packageValue":"Sign=WXPay",

        "nonceStr":"******",

        "timeStamp":"******",

        "sign":"******"

    }
}

HarmonyOS:

直接:


PayReq

↓

sendReq()

第五十一章 封装 PayManager

企业项目不要在页面写支付逻辑。

推荐:


export class PayManager {

    async pay(orderNo:string){

        // 1.获取支付参数

        // 2.构建PayReq

        // 3.调用微信

        // 4.等待回调

        // 5.查询订单

    }

}

页面:

只有:


await PayManager.getInstance().pay(orderNo)

即可。

所有支付细节:

全部隐藏。


第五十二章 支付结果监听

支付完成以后:

统一:

交给:


PayCallback

例如:


export interface PayCallback{

    onSuccess()

    onFail()

    onCancel()

}

页面:

实现:


class OrderPage implements PayCallback{

}

这样:

以后:

增加:

支付宝。

接口:

不用改。


第五十三章 支付状态同步

很多开发者:

收到:

微信:

成功。

立即:

跳:


支付成功

实际上:

企业:

一般:

先:


支付完成

↓

Loading

↓

查询订单

↓

SUCCESS

↓

支付成功

HarmonyOS:

例如:


while(true){

    const result = await queryOrder()

    if(result.status=="SUCCESS"){

        break

    }

}

但是:

不要:

无限循环。

建议:

最多:

查询:

5~6次。

采用:

指数退避:


2秒

↓

4秒

↓

8秒

↓

16秒

↓

停止

第五十四章 支付模块事件总线

支付:

通常:

多个页面:

需要:

监听。

例如:


订单页

购物车

我的订单

首页

建议:

使用:

EventHub。

例如:


eventHub.emit("PAY_SUCCESS", orderNo)

其它页面:


eventHub.on("PAY_SUCCESS",()=>{

})

这样:

支付完成:

购物车:

自动:

刷新。

订单:

自动:

刷新。

不用:

页面:

互相:

调用。


第五十五章 企业支付完整时序图


HarmonyOS App
      │
      ▼
创建订单
      │
      ▼
OrderService
      │
      ▼
MySQL 保存订单
      │
      ▼
统一下单
      │
      ▼
微信支付平台
      │
      ▼
返回 prepay_id
      │
      ▼
HarmonyOS 拉起微信
      │
      ▼
用户确认支付
      │
      ▼
微信 Notify
      │
      ▼
NotifyService
      │
      ▼
更新订单状态
      │
      ▼
HarmonyOS 查询订单
      │
      ▼
支付成功
      │
      ▼
刷新订单页面

整个过程中:

客户端只负责:

  • 创建订单请求
  • 获取支付参数
  • 拉起微信
  • 查询支付状态
  • 更新 UI

所有涉及:

  • 签名
  • 金额计算
  • 库存校验
  • 订单更新
  • 回调处理

全部由服务端完成。


企业开发经验总结

很多支付 Bug 都集中在以下几个方面:

问题 推荐方案
重复点击支付 按钮防抖 + 服务端幂等
重复 Notify 数据库唯一索引 + 幂等锁
超时未支付 定时关闭订单
支付成功未发货 以 Notify 为准,不以客户端为准
查询频繁 指数退避轮询
多端登录 支付结果通过事件同步
日志排查困难 全链路 TraceId

第五十六章 sendReq() 返回 true,但没有拉起微信

这是 HarmonyOS 接入微信支付最常见的问题之一。

很多开发者认为:


let result = await WXApi.sendReq(req)

if (result) {
    // 支付成功
}

实际上:

sendReq() 返回 true,只表示请求已经成功发送给微信 SDK。

并不表示:

  • 微信已经打开
  • 用户已经支付
  • 支付一定成功

真正流程:


sendReq()

↓

SDK接收请求

↓

尝试启动微信

↓

微信验证参数

↓

打开支付页面

任何一步失败,都可能导致:


没有拉起微信

排查顺序

建议按照下面顺序检查:

① 微信是否安装


await WXApi.isWXAppInstalled()

② SDK是否初始化

例如:


WXApi.registerApp(AppID)

是否执行。

建议:

应用启动立即初始化。

不要:

点击支付才初始化。


③ AppID是否一致

很多企业:

开发环境:


wx123

正式:


wx456

如果:

后台:

返回:

正式 AppID。

客户端:

初始化:

测试 AppID。

微信:

直接拒绝。


④ BundleName是否配置错误

HarmonyOS:

BundleName:

必须:

与微信开放平台:

一致。

例如:


com.demo.mall

不要:


com.demo.mall.test

企业建议

支付前:

统一检查:


checkWX()

↓

checkVersion()

↓

checkRegister()

↓

sendReq()

不要:

直接:

sendReq()


第五十七章 为什么 errCode=0 订单还是未支付?

很多新人:

看到:


errCode=0

立即:


支付成功

这是企业最严重的 Bug。

正确流程:


微信返回成功

↓

Notify

↓

服务器更新订单

↓

客户端查询订单

↓

SUCCESS

↓

支付成功

为什么?

例如:


微信支付完成

↓

服务器网络异常

↓

Notify失败

数据库:

还是:


UNPAID

如果:

客户端:

直接:

提示:

支付成功。

订单:

永远:

未支付。


正确方案


errCode=0

↓

queryOrder()

↓

SUCCESS

↓

支付成功

第五十八章 Notify 为什么收到两次?

很多开发者:

发现:


/pay/notify

收到:


2次

3次

10次

其实:

这是微信:

正常机制。

例如:

第一次:


Notify

↓

服务器超时

微信:

认为:

失败。

继续:

发送。

直到:

收到:


HTTP 200

才停止。


所以:

Notify:

必须:

幂等。

例如:


order_status

已经:


SUCCESS

直接:


return

不要:

再次:

扣库存。

不要:

再次:

发货。


第五十九章 为什么重复发货?

例如:

Notify:

第一次:


SUCCESS

发货。

第二次:

Notify:

再次:


SUCCESS

又:

发货。

怎么办?

建议:

增加:


delivery_status

例如:


WAIT

↓

DELIVERING

↓

SUCCESS

发货:

之前:

判断:


SUCCESS?

如果:

已经:

成功。

直接:

结束。


更推荐

数据库:

增加:


UNIQUE(transaction_id)

保证:

重复通知:

不会:

重复处理。


第六十章 为什么支付成功库存还是负数?

很多商城:

这样:

写:


支付成功

↓

库存--

如果:

Notify:

重复:

两次。

库存:


100

↓

99

↓

98

其实:

卖了一件。

库存:

减少:

两件。

正确:


SUCCESS?

↓

已处理?

↓

return

库存:

只扣:

一次。


推荐:

库存:

采用:


CAS

或者

Redis Lua

保证:

原子。


第六十一章 用户连续点击支付怎么办?

很多用户:


连续:

点击:

立即支付

结果:

服务器:

创建:

5个订单。

怎么办?

HarmonyOS:

建议:

按钮:


this.loading=true

支付:

结束:

恢复。

例如:


Button("立即支付")
.enabled(!this.loading)

服务端:

更加重要。

例如:

订单:

已经:


UNPAID

再次:

支付。

直接:

返回:

原订单。

不要:

重新:

创建。


第六十二章 用户支付过程中退出微信怎么办?

例如:


微信

↓

输入密码

↓

返回APP

订单:

到底:

成功了吗?

不能:

猜。

建议:

返回:

APP:

立即:

查询:


GET

/pay/query

如果:


PAYING

继续:

轮询。


企业建议

增加:

订单:


PAYING

状态。

不要:

只有:


UNPAID

SUCCESS

第六十三章 微信支付超时怎么办?

例如:

用户:

打开:

支付页面。

30分钟:

没付款。

怎么办?

微信:

订单:

会:

失效。

建议:

客户端:

收到:


ORDER_CLOSED

提示:


订单已失效

请重新下单

不要:

继续:

支付。


第六十四章 为什么支付成功没有收到 Notify?

原因:

通常:

以下几个:


公网无法访问

HTTPS错误

证书错误

防火墙

接口超时

DNS错误

企业:

上线:

第一件事:

不是:

测试:

支付。

而是:

测试:

Notify。

例如:


微信

↓

POST Notify

↓

服务器

↓

HTTP200

是否:

正常。


建议:

Notify:

日志:

永久:

保存。

例如:


notify_json

notify_time

headers

ip

以后:

查问题:

非常:

方便。


第六十五章 企业上线 Checklist(第一版)

正式上线前,请至少完成以下检查:

检查项 是否完成
微信 AppID 配置正确
商户号配置正确
API V3 Key 配置
商户私钥加载成功
平台证书下载成功
Notify 地址公网可访问
Notify 验签通过
Notify 幂等处理完成
订单状态流转正确
超时关闭订单
客户端二次确认订单
支付日志记录
TraceId 全链路跟踪
Redis 锁防止重复支付
压测通过

第六十六章 HarmonyOS NEXT 接入微信支付兼容性问题

HarmonyOS NEXT 与 Android 最大的区别之一,就是它已经不再兼容 Android APK,也没有 Android 的 Activity、Intent 等机制。因此,在迁移支付能力时,很多 Android 的经验不能直接照搬。

下面是企业项目中最常见的问题。


问题一:支付页面无法正常回调

现象:


微信支付完成

↓

没有返回应用

↓

应用一直停留在后台

原因可能包括:

  • 回调 Ability 配置错误
  • 应用未正确注册微信 AppID
  • 回调 Ability 未导出
  • Bundle Name 与微信开放平台配置不一致

建议检查:


EntryAbility

↓

WXEntryAbility

↓

AppScope

↓

module.json5

整个注册流程是否完整。


问题二:不同设备表现不一致

例如:


Mate70

正常支付

↓

Mate60

无法拉起微信

通常需要排查:

  • 微信版本是否一致
  • HarmonyOS NEXT 系统版本是否一致
  • 微信 SDK 是否为最新版本
  • OpenSDK 是否支持当前系统版本

企业建议:

建立设备兼容性测试矩阵,例如:

品牌 系统版本 微信版本 是否通过
Mate60 HarmonyOS NEXT 5.0 最新版
Mate70 HarmonyOS NEXT 5.1 最新版
Pura70 HarmonyOS NEXT 5.1 最新版
Mate X5 HarmonyOS NEXT 5.1 最新版

第六十七章 DevEco Studio 调试支付技巧

很多开发者第一次调试微信支付时:

日志非常少。

建议统一封装:


Logger.info("开始创建订单")

Logger.info("统一下单完成")

Logger.info("调用sendReq")

Logger.info("收到微信回调")

Logger.info("开始查询订单")

不要直接:


console.info(...)

推荐建立统一日志工具:


Logger

↓

Console

↓

File

↓

上传服务器

这样:

线上问题:

可以快速定位。


日志建议增加 TraceId

例如:


订单号:
202607060001

↓

TraceId:

f8ab-23ce-998d

以后:

所有:

接口:

统一:

携带:


X-Trace-Id

例如:


创建订单

↓

统一下单

↓

Notify

↓

查询订单

全部:

可以串起来。


第六十八章 多环境配置方案

企业:

一般:

至少:

四套环境。


dev

↓

test

↓

pre

↓

prod

不要:

代码:

这样:


const AppId="wx123456"

建议:

配置中心:


PayConfig

↓

开发环境

↓

测试环境

↓

生产环境

HarmonyOS:

例如:


PayConfig.getAppId()

而不是:

写死。


配置建议


config

├── dev.json

├── test.json

├── pre.json

└── prod.json

支付:

自动:

读取。


第六十九章 微信支付证书自动更新

很多企业:

支付:

突然:

全部:

失败。

原因:


平台证书

过期

解决方案:

不要:

人工:

更新。

建议:

后台:

每天:

自动:

检查:


微信平台证书

是否:

更新。

流程:


定时任务

↓

检查平台证书

↓

发现更新

↓

下载新证书

↓

热更新

避免:

凌晨:

全部:

支付失败。


第七十章 支付性能优化

很多项目:

一个支付:

耗时:


3秒

5秒

8秒

其实:

真正:

耗时:

通常:

在:

服务器。

建议:

拆解:

耗时:


创建订单

30ms

↓

统一下单

200ms

↓

数据库

20ms

↓

Redis

5ms

↓

返回客户端

统计:

每一步:

耗时。

不要:

只统计:

总耗时。


推荐监控

例如:


PayMonitor

↓

createOrder

↓

unifiedOrder

↓

notify

↓

queryOrder

每一步:

都有:

耗时。


第七十一章 高并发支付设计

例如:

618。

一分钟:


10万单

怎么办?

不要:

同步:

全部:

完成。

建议:


订单

↓

消息队列

↓

支付中心

↓

微信

例如:


RabbitMQ

或者

Kafka

订单:

异步:

处理。

客户端:

等待:

支付参数。


企业架构


Order

↓

MQ

↓

PayService

↓

WXPay

解耦:

订单:

支付。


第七十二章 支付监控平台

企业:

一般:

都有:

支付大屏。

例如:

实时:

显示:


支付成功率

↓

QPS

↓

退款数

↓

平均耗时

↓

异常数

建议:

Grafana:

例如:


今日支付:

10000

成功:

9988

失败:

12

发现:

异常:

立即:

报警。


第七十三章 支付告警系统

例如:

一分钟:

Notify:

失败:

100次。

怎么办?

立即:

通知:

运维。

建议:

接入:


短信

企业微信

钉钉

邮件

例如:


支付成功率

<95%

报警。

不要:

等:

用户:

投诉。


第七十四章 企业支付架构演进

小项目:

通常:


APP

↓

SpringBoot

↓

微信

几十万用户:

以后:

建议:


APP

↓

Gateway

↓

Order

↓

PayCenter

↓

WXPay

再大:

例如:

千万:

用户。

建议:


APP

↓

API Gateway

↓

Order Center

↓

Payment Center

↓

MQ

↓

Notify Center

↓

Message Center

↓

Inventory Center

支付:

独立:

成为:

支付中心。

方便:

支付宝、

微信、

云闪付、

Apple Pay、

数字人民币

统一:

管理。


第七十五章 企业级支付架构(最终版)


                    HarmonyOS APP
                           │
                           ▼
                      API Gateway
                           │
            ┌──────────────┼──────────────┐
            ▼              ▼              ▼
      Order Center    User Center    Coupon Center
            │
            ▼
      Payment Center
            │
    ┌───────┼────────┐
    ▼       ▼        ▼
 WeChat   Alipay   UnionPay
            │
            ▼
      Notify Center
            │
            ▼
      Message Queue
            │
            ▼
 Inventory / Logistics / Message

这种架构有几个优势:

  1. 支付渠道统一:微信、支付宝、云闪付使用统一接口。
  2. 高扩展性:新增支付渠道几乎不影响业务层。
  3. 高可用:支付中心可独立扩容、独立部署。
  4. 便于监控:支付链路集中管理。

经过大量项目实践,推荐遵循以下原则:

场景 推荐方案
支付入口 PayManager 统一管理
支付渠道 策略模式(Strategy)
支付回调 事件总线(EventHub)
支付状态 服务端统一维护
订单查询 指数退避轮询
日志 TraceId + 全链路日志
配置 多环境配置中心
高并发 MQ 解耦支付流程
告警 实时监控 + 自动通知

第76章 企业级 PayManager 完整设计

在很多公司的项目中,页面(Page) 是绝对不能直接调用微信 SDK 的。

很多初学者会这样写:


Button("立即支付")
.onClick(async () => {
    const payData = await Http.post("/pay/create")
    const req = new PayReq()
    req.appId = payData.appId
    req.partnerId = payData.partnerId
    ...
    await WXApi.sendReq(req)
})

虽然能够运行,但是存在很多问题:

  • 页面代码过于臃肿
  • 无法复用
  • 后续接入支付宝需要修改所有页面
  • 难以单元测试
  • 不方便统一日志和异常处理

因此,企业项目一般会采用如下结构:


PayManager
    │
    ├── PayRepository
    ├── WXManager
    ├── PayDispatcher
    ├── PayEventCenter
    └── OrderRepository

页面只负责:


await PayManager.getInstance().pay(orderNo)

第77章 PayManager 职责划分

一个优秀的 PayManager 不应该只有一个 pay() 方法,而应该承担整个支付生命周期的管理。

例如:


export class PayManager {

    async createOrder() {}

    async createPay() {}

    async startWechatPay() {}

    async queryPayResult() {}

    async cancelPay() {}

}

每一个方法都有独立职责:


createOrder()
        │
        ▼
创建业务订单

createPay()
        │
        ▼
获取微信支付参数

startWechatPay()
        │
        ▼
拉起微信

queryPayResult()
        │
        ▼
确认订单状态

cancelPay()
        │
        ▼
取消支付流程

这样后续维护成本会低很多。


第78章 Repository 模式

企业项目一般不会让 PayManager 直接请求网络。

推荐增加:


PayRepository

负责所有支付接口。

例如:


export default class PayRepository {

    async createPay(orderNo: string) {
        return await PayApi.createPay(orderNo)
    }

    async queryOrder(orderNo: string) {
        return await PayApi.queryOrder(orderNo)
    }

}

这样:

如果以后:

HTTP 框架:


Axios

↓

OkHttp

↓

自研HTTP

页面和业务层都不需要修改。


第79章 WXManager 封装

所有微信 SDK 调用,都建议集中管理。

例如:


export class WXManager {

    async register() {}

    async sendPayRequest() {}

    async isWXInstalled() {}

    async isSupportPay() {}

}

支付时:


await WXManager.getInstance().sendPayRequest(req)

不要在多个页面重复:


WXApi.sendReq(...)

统一封装的好处:

  • 统一异常处理
  • 统一日志
  • 统一版本兼容
  • 后续 SDK 升级只改一处

第80章 EventHub 支付事件设计

支付完成后,通常需要通知多个页面。

例如:


支付成功
    │
    ├── 订单页刷新
    ├── 首页刷新
    ├── 购物车刷新
    ├── 我的订单刷新
    └── 用户积分刷新

如果页面之间直接互相调用,耦合会越来越高。

推荐定义统一事件:


export enum PayEvent {

    PAY_SUCCESS,

    PAY_CANCEL,

    PAY_FAIL

}

支付成功:


eventHub.emit(PayEvent.PAY_SUCCESS, orderNo)

任何页面:


eventHub.on(PayEvent.PAY_SUCCESS, (orderNo) => {

})

即可监听。


第81章 支付状态机设计

不要使用:


支付成功

支付失败

两个状态。

建议完整生命周期:


CREATED
    │
    ▼
WAIT_PAY
    │
    ▼
PAYING
    │
    ▼
SUCCESS
    │
    ▼
FINISHED

异常流程:


WAIT_PAY
      │
      ├── CANCEL
      │
      ├── CLOSE
      │
      └── REFUND

建议定义枚举:


export enum PayStatus {

    CREATED,

    WAIT_PAY,

    PAYING,

    SUCCESS,

    FINISHED,

    CANCEL,

    CLOSED,

    REFUNDING,

    REFUNDED

}

所有页面统一使用,不要写 "SUCCESS""PAID" 之类的字符串。


第82章 企业级异常处理

不要:


try{

}catch(e){

}

什么都不做。

建议统一异常:


PayException

例如:


export class PayException {

    code:number

    message:string

}

统一错误码:

Code 含义
1001 微信未安装
1002 微信版本过低
1003 订单不存在
1004 统一下单失败
1005 签名失败
1006 订单已关闭
1007 订单已支付

这样 UI 可以根据错误码做不同提示,而不是只弹一个“支付失败”。


第83章 日志系统设计

建议整个支付链路都有统一日志。

例如:


[Pay]
创建订单

↓

统一下单

↓

拉起微信

↓

收到回调

↓

查询订单

↓

完成

推荐封装:


PayLogger.info()

PayLogger.warn()

PayLogger.error()

而不是项目里到处都是:


console.info(...)

日志中建议包含:

  • TraceId
  • OrderNo
  • UserId(脱敏)
  • 耗时
  • 错误码
  • 当前支付阶段

第84章 支付模块单元测试

支付模块也是可以测试的。

例如:

模拟:


创建订单成功

↓

统一下单失败

或者:


微信未安装

甚至:


Notify 延迟 10 秒

通过 Mock PayRepositoryWXManager,可以覆盖大部分业务逻辑,而无需真实调用微信 SDK。

建议重点测试:

  • 重复点击支付
  • 网络超时
  • 查询订单失败
  • 用户取消支付
  • 回调重复触发

第85章 企业级客户端 SDK 最终结构

最终推荐结构如下:


pay
├── api
│     PayApi.ets
│
├── repository
│     PayRepository.ets
│
├── manager
│     PayManager.ets
│     WXManager.ets
│
├── callback
│     PayCallback.ets
│
├── event
│     PayEvent.ets
│
├── model
│     PayRequest.ets
│     PayResponse.ets
│     PayResult.ets
│
├── exception
│     PayException.ets
│
├── logger
│     PayLogger.ets
│
└── utils
      PayUtils.ets

整个客户端对外暴露的接口尽量保持简单:


await PayManager.getInstance().pay(orderNo)

第86章 企业级支付模块初始化

经过前面的章节,我们已经完成了支付架构设计。

现在开始正式搭建支付模块。

建议采用独立业务模块:


entry
├── common
├── network
├── order
├── user
├── pay
│   ├── api
│   ├── manager
│   ├── model
│   ├── repository
│   ├── callback
│   ├── event
│   ├── exception
│   ├── utils
│   └── logger
└── pages

这样支付相关代码全部集中管理,不会散落在页面中。


为什么支付要独立模块?

支付通常会被多个业务复用:

  • 商品购买
  • VIP 会员
  • 课程购买
  • 充值
  • 打赏
  • 活动报名

如果每个页面都写一套支付逻辑,维护成本会越来越高。

因此推荐统一入口:


PayManager

所有业务都调用同一个支付模块。


第87章 支付配置中心

不要在代码中直接写:


微信 AppID

商户号

服务器地址

推荐统一配置:


PayConfig

负责:

  • 支付环境
  • 支付渠道
  • 请求超时时间
  • 日志等级
  • 回调地址(由服务端管理)

配置中心的职责是读取配置,而不是保存任何敏感密钥。


多环境切换

建议支持:


dev
test
pre
prod

每个环境使用不同:

  • App 配置
  • 服务端地址
  • 日志级别

避免开发环境误调用生产服务。


第88章 支付生命周期

企业支付建议定义统一生命周期:


初始化
   │
   ▼
创建订单
   │
   ▼
获取支付参数
   │
   ▼
发起支付
   │
   ▼
等待回调
   │
   ▼
查询订单
   │
   ▼
完成

所有阶段建议统一记录日志,方便定位问题。


第89章 Repository 与 Manager 的职责

建议职责明确:

Repository:

负责:

  • 请求服务端接口
  • 数据转换
  • 网络异常处理

Manager:

负责:

  • 支付流程控制
  • 调用微信 SDK
  • 回调处理
  • 状态同步
  • 事件通知

这样网络层和业务层完全解耦。


第90章 页面如何调用支付?

页面应保持尽可能简单。

推荐流程:


点击立即支付
      │
      ▼
PayManager
      │
      ▼
Repository
      │
      ▼
服务端
      │
      ▼
微信支付

页面只需要关心:

  • 显示 Loading
  • 响应支付结果
  • 刷新订单

而无需了解支付实现细节。


本章小结

本章完成了企业级支付模块初始化设计,包括:

  • 支付模块目录规划
  • 配置中心设计
  • 多环境管理
  • 支付生命周期
  • Repository 与 Manager 分层
  • 页面调用规范

第91章 服务端统一下单接口设计

客户端点击"立即支付"后,第一步不是调用微信,而是请求自己的业务服务器

整体流程如下:


HarmonyOS App
      │
      │ POST /api/pay/create
      ▼
业务服务器
      │
      │ 校验订单
      │ 校验金额
      │ 校验库存
      ▼
微信支付统一下单
      │
      ▼
返回预支付信息
      │
      ▼
业务服务器签名
      │
      ▼
HarmonyOS App

统一下单接口建议保持职责单一:

  • 校验订单是否合法
  • 判断订单是否已支付
  • 调用微信支付统一下单
  • 返回客户端发起支付所需参数

不要在这个接口中处理:

  • 发货
  • 扣积分
  • 修改订单状态为成功

这些都应该等待支付结果确认后再执行。


第92章 创建订单接口设计

建议支付前先创建业务订单。

例如:


POST /api/order/create

请求:


{
  "goodsId": 10001,
  "count": 2,
  "couponId": 8
}

返回:


{
  "code": 0,
  "data": {
    "orderNo": "202607060001"
  }
}

订单创建成功后:

数据库状态:


WAIT_PAY

而不是:


SUCCESS

为什么要先创建订单?

如果:


先微信支付

↓

再创建订单

那么:

一旦:

数据库:

异常。

用户:

已经:

付款。

订单:

不存在。

企业:

几乎:

无法恢复。

所以:

必须:


创建订单

↓

统一下单

↓

支付

第93章 幂等设计

支付系统:

最重要:

两个字:

幂等

例如:

用户:

连续点击:


立即支付

十次。

不能:

创建:

十个订单。

建议:

数据库:

增加:


business_no

或者:


request_id

作为:

幂等键。

流程:


收到请求

↓

检查request_id

↓

存在

↓

直接返回

↓

不存在

↓

创建订单

Notify 也要幂等

微信:

可能:

重复:

通知。

例如:


SUCCESS

↓

SUCCESS

↓

SUCCESS

业务:

只能:

处理:

一次。

建议:

更新订单:

采用:


update t_order
set status='SUCCESS'
where order_no=?
and status='WAIT_PAY'

如果:

更新:

0 行。

说明:

已经:

处理。

直接:

返回。


第94章 订单状态流转

建议:

完整状态:


CREATED
      │
      ▼
WAIT_PAY
      │
      ▼
PAYING
      │
      ▼
SUCCESS
      │
      ▼
DELIVERING
      │
      ▼
FINISHED

异常:


WAIT_PAY

├── CLOSED

├── CANCELLED

└── REFUNDING

不要:

只有:


0

1

两个状态。

后期:

维护:

非常困难。


第95章 回调后的业务处理

微信通知:

支付成功。

第一件事情:

不是:

发货。

正确流程:


Notify

↓

验签

↓

更新订单

↓

记录支付流水

↓

发送MQ消息

↓

库存系统

↓

积分系统

↓

物流系统

↓

消息中心

这样:

支付:

与:

业务:

彻底:

解耦。


为什么使用 MQ?

例如:

支付成功。

如果:

同步:

调用:


库存

↓

积分

↓

优惠券

↓

短信

其中:

短信:

超时。

整个:

支付:

都会:

变慢。

所以:

推荐:


Notify

↓

MQ

↓

库存服务

↓

积分服务

↓

消息服务

异步:

消费。


第96章 支付流水设计

订单:

不能:

代替:

支付流水。

建议:

独立:


t_pay_order

记录:

  • 商户号
  • 微信交易号
  • 支付金额
  • 支付时间
  • 支付状态
  • 原始返回数据(必要时脱敏存储)

这样:

后期:

对账:

退款:

都会:

方便很多。


第97章 对账机制

每天:

建议:

执行:


下载微信账单

↓

比对数据库

↓

发现差异

↓

自动补偿

↓

人工处理

不要:

认为:

Notify:

100%

可靠。

任何:

支付系统:

都需要:

每日:

对账。


第98章 支付安全建议

企业:

上线:

至少:

做到:

以下:

几点:

  • 全站 HTTPS
  • 服务端验签
  • 不在客户端保存商户密钥
  • 敏感日志脱敏
  • 支付接口限流
  • 防重放(Nonce、时间戳等按协议要求处理)
  • 风险订单二次验证

第99章 上线前压测

建议:

模拟:


1000

↓

5000

↓

10000

↓

50000

并发:

支付。

观察:

  • 数据库
  • Redis
  • MQ
  • CPU
  • 内存
  • 平均响应时间

提前:

发现:

瓶颈。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐