2026-04-02 05:26:11 -05:00
's'
2026-04-02 05:26:11 -05:00
2026-01-01 19:52:27 +08:00
2026-03-13 10:59:27 -05:00
's'
2026-03-27 18:20:43 -05:00
's'
2026-03-27 18:20:43 -05:00
s
2026-03-26 15:37:41 +08:00
2026-01-01 19:52:27 +08:00
2026-01-01 19:52:27 +08:00
's'
2026-03-10 05:25:08 -05:00
's'
2026-04-01 02:23:37 -05:00
's'
2026-03-31 12:45:04 -05:00
2026-03-13 05:15:00 -05:00
2026-03-13 05:15:00 -05:00
2026-03-13 05:15:00 -05:00
2026-01-01 19:52:27 +08:00
s''
2026-03-10 04:42:05 -05:00

PayJS API

支付 API 服务支持多支付渠道XorPay、ZPAY按项目模块化拆分。

路由与项目对应

项目 路由前缀 说明
nomadvip /nomadvip/* 固定 ZPAY独立实例
digital /digital/* 使用 PAYMENT_PROVIDER
cnomadcna /cnomadcna/* 使用 PAYMENT_PROVIDER
nomadlms /nomadlms/* 使用 PAYMENT_PROVIDER
legacy /payh5/zpay_notify 向后兼容

各项目业务互不影响,可单独配置。

环境

本地调试:BASE_URL 需为 ZPAY 可访问地址(如 ngrok 暴露 8700 端口)
线上部署:BASE_URL=https://api.hackrobot.cn

模块结构

app/
├── config.py          # 配置(环境变量)
├── main.py            # FastAPI 入口,挂载路由
├── sdk/               # SDK 组件化封装
│   ├── payment/       # 支付网关ZPAY/XorPay
│   ├── pocketbase.py  # PocketBase 数据库
│   ├── minio.py       # MinIO 对象存储
│   └── memos.py       # Memos 用户(仅 nomadvip 使用)
├── services/          # 共享业务逻辑(基于 SDK
│   ├── pb.py          # PocketBase 客户端
│   ├── memos.py       # Memos 用户创建
│   ├── minio.py       # MinIO 上传
│   └── payment.py     # 支付成功处理
├── routers/           # 项目路由
│   ├── nomadvip.py    # /nomadvip/*
│   ├── digital.py    # /digital/*
│   ├── cnomadcna.py  # /cnomadcna/*
│   ├── nomadlms.py   # /nomadlms/*
│   ├── legacy.py     # /payh5 等(向后兼容)
│   └── common.py     # /submit_meetup_application、/create_user
└── payment/
    ├── base.py        # 支付抽象基类
    ├── xorpay.py      # XorPay 实现
    ├── zpay.py        # ZPAY 实现(易支付兼容)
    └── factory.py     # 渠道工厂

支付渠道

渠道 环境变量 说明
XorPay PAYMENT_PROVIDER=xorpay 默认
ZPAY PAYMENT_PROVIDER=zpay 需配置 ZPAY_PIDZPAY_KEY

切换渠道:设置环境变量 PAYMENT_PROVIDER=xorpayzpay,参考 .env.example

本地调试

# 复制配置
cp .env.example .env

# 本地调试时 BASE_URL 需 ZPAY 可访问,可用 ngrok
# ngrok http 8700  -> 将 BASE_URL 设为 ngrok 提供的 https 地址

python run.py
# 或 uvicorn app.main:app --host 0.0.0.0 --port 8700 --reload

线上部署

域名:https://api.hackrobot.cn

# .env 中设置
BASE_URL=https://api.hackrobot.cn
PAYMENT_PROVIDER=zpay
# 其他 ZPAY、PocketBase、Memos 配置见 .env.example

线上「支付失败」排查

本地正常、Ubuntu 部署后 api.hackrobot.cn 调用支付失败,常见原因:

  1. BASE_URL 配置错误:必须为 ZPAY 可公网访问的地址。错误示例:http://127.0.0.1:8700http://localhost。正确:https://api.hackrobot.cn域名需解析到本机nginx 反向代理对应端口)。

  2. 服务器无法访问 zpayz.cn防火墙、DNS 或网络限制。访问 https://api.hackrobot.cn/health?check_zpay=1 自检:

    • zpayz_reachable: false → 开放出站或检查网络
    • zpayz_error 含 "SSL" → 执行 apt install ca-certificates 后重启
  3. client_ip 内网导致 ZPAY 风控拒单前端digital/cnomadcna/nomadvip通过 nginx 代理时,需配置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for,否则 payjsapi 收到 127.0.0.1 会触发风控。已做兼容:内网 IP 时自动省略 clientip 参数。

  4. 启动时控制台有 BASE_URL 警告:说明配置了内网地址,需修改 .env 中的 BASE_URL 为公网地址后重启。

  5. 查看详细错误支付失败时payjsapi 会输出 ZPAY create_order_api 失败 日志,含 status/code/msg便于定位。

自检结果2026-04-01

本次联动自检覆盖了 nomadvip 前端与本仓库 nomadvip 路由的支付闭环:

  • 创建订单:/nomadvip/payh5/nomadvip/payh5/redirect
  • 异步通知:/nomadvip/xorpay_notify/nomadvip/zpay_notify
  • 支付查询:/nomadvip/order_status
  • VIP 识别:/nomadvip/check_vip/nomadvip/check_vip_by_email

发现问题

  • 业务链路问题发生在前端 nomadvip/api/pay/confirm 兜底写 payments 时使用默认金额,可能与实际支付金额不一致(例如测试价、活动价)。

处理状态

  • 已在前端仓库修复confirm 兜底写库时优先使用网关返回 pay_price,失败才回退默认金额。
  • 本仓库暂未发现新的阻断型业务 bug以静态代码审阅为准

维护建议

  • 建议保持 payjsapi 为唯一支付入账源,前端 confirm 仅作为短时兜底。
  • 建议为 order_status 返回结构固定增加字段约束(如统一返回 pay_price 字段),避免调用侧重复兼容。
Description
No description provided
Readme 1.8 MiB
Languages
Python 99.6%
Shell 0.4%