Skip to content

常见问题

更新时间:2026/8/22 12:13:45

汇总 DaxPay 使用、部署、二次开发中高频出现的疑问。未覆盖的问题可至 GitHub Issues交流群 反馈。

基础概念

DaxPay 是什么

DaxPay 是一款开源支付系统,提供支付、退款、查询、回调等支付核心能力,将支付宝、微信、银联等多种支付通道封装为统一的 HTTP 接口,业务系统只需对接一套标准协议即可接入多种支付方式。详见 项目介绍

开源版和商业版有什么区别

开源版(本项目)交付完整的支付核心链路与多端管理界面,基于 LGPL v3.0 协议开源。

商业版(dax-pay-plus)在开源版基础上扩展:

  • 更多聚合通道 — 20+ 渠道子模块
  • 结算中心更多国际支付通道等增强能力

转账与分账已包含在开源版交付范围内。

LGPL v3.0 协议可以商用吗

可以。LGPL v3.0 允许商业使用。你的业务系统可以通过接口调用或动态链接方式使用 DaxPay,无需开源你的业务代码。详见 开源协议

部署运行

后端编译必须用 mvnd 吗

项目约定使用 mvnd(Maven Daemon)加速编译。普通 mvn 也能编译,但 mvnd 自带守护进程,增量编译速度显著更快,推荐使用。

Apache Artemis 能否替换为其他消息队列

当前版本强依赖 Artemis(用于支付延时通知等 JMS 场景),不支持直接替换为 RabbitMQ / Kafka。如需替换需自行改造消息中间件适配层。

延时消息提前或延后投递怎么办

现象:延时消息设置 10 秒,约 6 秒就被消费;或设置 5 秒,过了 8 秒才收到。

原因:Artemis 延时消息按绝对时间戳投递 —— 发送端用本机时钟计算「当前时间 + 延时」写入消息属性,broker 等到自己的时钟到达该时间戳才投递。当应用与 broker 跨机器部署且两机时钟不一致时,实际延时会平移两机时钟差:

  • 应用机器时钟于 broker → 消息提前投递(如本例慢约 4 秒,10 秒延时约 6 秒即送达)
  • 应用机器时钟于 broker → 消息延后投递

排查:对比两机时钟。可借 broker 主机上任意 HTTP 服务(如 Artemis 控制台 8161 端口)的响应 Date 头与本机时间比对:

bash
curl -sI http://<broker主>:8161/ | grep -i '^date'   # broker 侧时间(秒级精度)
date                                                    # 本机时间

修复:两台机器均开启 NTP 对时。

Linux 服务器(broker 所在主机):

bash
timedatectl                          # 查看 "System clock synchronized" 与 "NTP service" 状态
sudo timedatectl set-ntp true        # 未开启时先开启 timesyncd
# 系统未装 timesyncd 时,安装 chrony 接管(RHEL 系用 dnf,服务名为 chronyd):
sudo apt install chrony && sudo systemctl enable --now chrony
chronyc tracking                     # 验证:Leap status 为 Normal 即已同步

Windows 开发机(本地跑后端连远程 broker 的场景):

powershell
w32tm /query /status                 # 查看时间服务状态与上次成功同步时间
# 以下两条需管理员终端执行:
w32tm /resync                        # 立即校时(机器休眠唤醒后时钟漂移,可手动执行)
w32tm /config /syncfromflags:manual /manualpeerlist:"ntp.aliyun.com time.windows.com" /update
                                     # time.windows.com 通路不稳时切换国内 NTP 源

TIP

官方安装器部署中,应用与 Artemis 为同一宿主机上的容器,共享内核时钟,天然不存在此问题。该问题常见于「本地跑后端 + 远程 broker」的开发拓扑,以及自行跨机部署 broker 的场景 —— 跨机部署时 NTP 对齐是延时消息精度的硬前提。

套了 CDN 后登录报「请求验证已失效」或「请求时间戳已过期」怎么办

现象:本地直连后端一切正常,套上 CDN(腾讯 EdgeOne、CloudFlare 等)后登录必报 「请求验证已失效,请重试」或「请求时间戳已过期,请重试」。

原因:登录防重放机制要求每次登录先取一个一次性 nonce,CDN 把这个 GET 接口的响应缓存后, 所有用户拿到同一份旧 nonce —— 缓存 5 分钟内报前者(nonce 已被消费),超 5 分钟报后者(时间戳超容差)。 图形验证码接口被缓存同理(所有人看到同一张图)。

排查:用一个仍是 GET 的接口(如公钥)连续请求两次,观察缓存状态:

bash
curl -sD - -o /dev/null https://你的域名/api/token/public-key | grep -i "cache-status"
# EO-Cache-Status: HIT 说明命中缓存(腾讯 EdgeOne;CloudFlare 看 CF-Cache-Status)

修复:在 CDN 给所有 API 路径(/api/* 及网关域名的 /unipay/*/client/*)配置不缓存规则, 详见 CDN 部署注意事项

支持哪些数据库

仅支持 PostgreSQL 14+。时间字段统一使用 timestamptz(6),实体类使用 OffsetDateTime,不支持 MySQL / Oracle 等。

容器化部署最低配置

建议最低 2 核 4G(含 PostgreSQL / Redis / Artemis / 主应用 / 通道子应用全部容器化)。生产环境建议 4 核 8G 起步,并根据交易量水平扩展通道子应用实例。

PowerShell 下 mvnd 编译参数报错

PowerShell 下含 =-D 参数会被空格拆分,必须加引号:

powershell
# 错误 — 会被拆分
mvnd compile -Dmaven.test.skip=true

# 正确 — 加引号
mvnd compile "-Dmaven.test.skip=true"

详见 项目构建

通道对接

开源版已支持哪些支付通道

已对接 13 个国内支付通道:

  • 直连通道(channel-one)— 支付宝、微信、抖音、银联商务、银联(云闪付)
  • 聚合通道(channel-two)— 拉卡拉、海科融通、斗拱(汇付天下)、乐刷、随行付、河马付(杉德)、Adapay、富友

详见 特色功能 - 通道总数与分布

如何新增一个支付通道

  1. 在对应通道子应用(直连走 channel-one,聚合走 channel-two)的 daxpay-channel-impl 下实现 SDK 调用与签名/验签
  2. 在主应用 daxpay-channel 注册通道策略与配置数据 CRUD
  3. ChannelEnum 补充通道枚举

新增通道只需实现 SDK 调用并注册策略,不影响主链路。

channel-one / channel-two / channel-three 有什么区别

三者架构完全相同,区别在于承载的通道集合:

  • channel-one — 对接支付宝、微信等直连通道(官方 SDK)
  • channel-two — 对接拉卡拉、富友等聚合通道(聚合 SDK)
  • channel-three — 对接 Stripe 等国际通道

主应用通过 daxpay.channel.one/two/three.base-url 路由,子应用编号固定不可改名。

通道子应用的 Java 版和 Go 版怎么选

channel-one 同时提供 Java(Spring Boot)与 Go(Gin)两套完全对等的实现,端口、路由、响应契约一致:

  • Java 版 — 生态完整,通道官方 SDK 现成,适合快速对接
  • Go 版 — 更高吞吐、更低内存占用,全部自研 HTTP 签名对接(无第三方 SDK)

按团队技术栈与性能诉求选用,两者二选一,端口冲突不可同时启动

通道子应用必须独立部署吗

是的。通道子应用独立部署是 DaxPay 的核心设计 —— 将第三方 SDK 隔离到子应用,避免 SDK 依赖污染主应用,支持独立升级与弹性伸缩。主应用通过 @HttpExchange 声明式 HTTP 客户端调用子应用,链路 AES-GCM 加密。

功能边界

是否支持分账 / 提现

分账已支持:支付宝、微信、抖音三通道直连商户分账。使用流程:统一下单时声明 allocation=true 创建分账订单 → 通过开放接口 发起分账 / 查询 / 同步;分账接收方需提前在通道侧完成绑定(管理端「通道商户详情 → 分账接收方」提供绑定入口)。详见接口文档

提现(代付)暂未实现,属后续增强方向。

是否支持国际支付(PayPal / Stripe)

Stripe 已通过 channel-three 子应用接入(持续完善中),支持国际卡组织支付。PayPal 等其他国际通道为后续规划。

沙箱环境怎么用

DaxPay 采用部署级沙箱隔离:

  • 测试 / 开发环境配置 daxpay.platform.config.sandbox-enabled=true,允许沙箱联调
  • 生产环境必须配置 sandbox-enabled=false,启动时会强制将所有 activeEnv=sandbox 的产品重置为 prod,保证生产数据纯净

生产环境隔离

沙箱联调请走独立的测试环境部署,生产数据库严禁从测试环境导入数据。详见 配置说明

是否支持多商户 / 多商户隔离

支持。DaxPay 原生支持多商户模式:

  • 运营端 + 商户端双入口,数据行级隔离(商户编号自动隔离)
  • 单商户可配置多个支付应用,独立凭证与回调地址

二次开发

能否修改源码用于自己的项目

可以。基于 LGPL v3.0,你可以自由修改、使用源码。若你修改了 DaxPay 库本身(而非通过接口调用),需以 LGPL 协议开源你的修改;若仅通过接口调用或动态链接,你的业务代码无需开源。

前端如何对接后端接口

前端通过 RESTful HTTP 接口对接主应用(端口 9999),接口请求 / 响应支持 RSA 签名防篡改,认证基于 Sa-Token(token name: Accesstoken)。详细接入方式见 接口文档

如何新增一种界面语言(i18n)

  • 后端 — 资源文件在 common-i18n/src/main/resources/i18n/{locale}/,按业务模块拆分,新增语种需同步维护 zh-CN / en-US / zh-TW / zh-HK / ja-JP / ko-KR
  • 前端(Web/H5) — 10 语种,新增 key 需全语种同步
  • 小程序 — 仅中英(小程序端条件编译剔除繁体 / 日韩 / 东盟)

详见各端 i18n 规范。

数据库表结构在哪?如何初始化

SQL 脚本位于 dax-pay-open/_config/sql/,全新安装顺序为 tables.sql(建表)→ datas.sql(初始数据)。仓内另提供升级脚本 update-tables.sqlupdate-datas.sql 与菜单种子 iam_perm_menu.sql

注意

全量 tables.sql / datas.sql 不在仓库内(体积大),需从飞书安装包或历史版本获取。仓内 README.md 有说明。

为什么缓存会出现「只读 L1、不读写 Redis」的情况

MultiLevelCache#isL1Only 源码时容易疑惑:普通缓存只有「L1+L2 双层」和「仅 L2」(纯 Redis 模式)两种形态,为什么还存在「仅 L1」?

这不是普通缓存的常规形态,而是敏感缓存的安全降级保护。当缓存名命中敏感名单(secure: 前缀或 secureNames 配置)、且平台数据加密未启用时,敏感数据被禁止明文写入 Redis,此时:

  • 写侧:仅写 L1 本机内存,不写 Redis;
  • 读侧:连 L2 也不查,直接穿透到方法重新加载。

读侧跳过 L2 是 fail-safe 设计——Redis 里可能存在三类脏数据:①曾启用加密后关闭残留的密文(当前无法解密);②加密启用前明文写入的历史数据(无保护);③多节点密钥版本不一致的密文(解密失败)。宁可穿透重查,也不能把不对的数据当缓存值返回。

完整的缓存行为矩阵:

缓存类型条件读行为
普通缓存enabled=true, l1.enabled=trueL1 → L2
普通缓存enabled=true, l1.enabled=false仅 L2(纯 Redis 模式)
普通缓存enabled=falseNoOp 穿透
敏感缓存数据加密启用L1 → L2(L2 整包 AES-GCM 加密)
敏感缓存数据加密启用仅 L1(本条目,安全降级)
敏感缓存加密未启用 + l1.enabled=false完全穿透(实质不缓存)

一旦启用数据加密,敏感缓存即自动恢复 L1+L2 双层形态(仅 L2 value 为密文)。应用启动时若命中该降级分支,日志会输出 WARN「敏感缓存因未启用数据加密,仅使用 L1 本地缓存,不写 Redis」提示。


未找到答案?欢迎到 GitHub Issues 提问或加入 交流群 讨论。

基于 GNU LGPL v3.0 协议开源