This commit is contained in:
eric
2026-03-10 07:05:35 -05:00
parent 65d7047534
commit ddbf30652c
4 changed files with 60 additions and 4 deletions

View File

@@ -6,8 +6,12 @@
# 本地调试ngrok 暴露 8700 后设置 BASE_URL=https://xxx.ngrok.io # 本地调试ngrok 暴露 8700 后设置 BASE_URL=https://xxx.ngrok.io
# 线上部署BASE_URL=https://api.hackrobot.cn # 线上部署BASE_URL=https://api.hackrobot.cn
# ========== 生产部署 ========== # ========== 生产部署Ubuntu 等)==========
# BASE_URL 必须为 payjsapi 实际公网地址ZPAY 异步通知会请求此地址 # 线上部署必须正确配置,否则会显示「支付失败」:
# 1. BASE_URL 必须为 payjsapi 公网地址ZPAY 需能访问此地址做异步回调
# 错误示例http://127.0.0.1:8700、http://localhostZPAY 无法访问)
# 正确示例https://api.hackrobot.cn域名需解析到本机并配置 nginx 反向代理)
# 2. 服务器需能访问 zpayz.cn检查防火墙、DNS可访问 /health?check_zpay=1 自检
BASE_URL=https://api.hackrobot.cn BASE_URL=https://api.hackrobot.cn
# 支付渠道zpay已替代 xorpay| xorpay # 支付渠道zpay已替代 xorpay| xorpay

View File

@@ -82,6 +82,16 @@ PAYMENT_PROVIDER=zpay
# 其他 ZPAY、PocketBase、Memos 配置见 .env.example # 其他 ZPAY、PocketBase、Memos 配置见 .env.example
``` ```
## 线上「支付失败」排查
本地正常、Ubuntu 部署后显示支付失败,常见原因:
1. **BASE_URL 配置错误**:必须为 ZPAY 可公网访问的地址。错误示例:`http://127.0.0.1:8700``http://localhost`。正确:`https://api.hackrobot.cn`域名需解析到本机nginx 反向代理 8700 端口)。
2. **服务器无法访问 zpayz.cn**防火墙、DNS 或网络限制。访问 `https://你的域名/health?check_zpay=1` 自检,若 `zpayz_reachable: false` 则需开放出站或检查网络。
3. **启动时控制台有 BASE_URL 警告**:说明配置了内网地址,需修改 `.env` 中的 `BASE_URL` 为公网地址后重启。
## Getting started ## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps. To make it easy for you to get started with GitLab, here's a list of recommended next steps.

View File

@@ -11,14 +11,16 @@
- common: /submit_meetup_application、/create_user - common: /submit_meetup_application、/create_user
本地调试BASE_URL 需为 ZPAY 可访问地址(如 ngrok 本地调试BASE_URL 需为 ZPAY 可访问地址(如 ngrok
线上部署https://api.hackrobot.cn 线上部署:BASE_URL=https://api.hackrobot.cn(必须为 ZPAY 可公网访问的地址)
""" """
import logging import logging
import requests
from fastapi import FastAPI, Request, HTTPException from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from .config import BASE_URL
from .routers import ( from .routers import (
nomadvip_router, nomadvip_router,
digital_router, digital_router,
@@ -58,6 +60,38 @@ logging.basicConfig(
handlers=[logging.StreamHandler()], handlers=[logging.StreamHandler()],
) )
# 启动时校验 BASE_URL线上部署必须为公网可访问地址否则 ZPAY 无法回调)
def _check_base_url():
url = (BASE_URL or "").strip().lower()
if not url:
logging.warning("BASE_URL 未设置,将使用默认值。线上部署请务必设置 BASE_URL 为公网地址")
return
if "localhost" in url or "127.0.0.1" in url or url.startswith("http://192.168.") or url.startswith("http://10."):
logging.warning(
"BASE_URL=%s 疑似内网地址ZPAY 无法回调!线上部署请设置 BASE_URL 为公网地址,如 https://api.hackrobot.cn",
BASE_URL,
)
@app.on_event("startup")
async def startup_event():
_check_base_url()
@app.get("/health")
async def health(check_zpay: str = ""):
"""健康检查。check_zpay=1 时额外检测 zpayz.cn 连通性"""
out = {"status": "ok", "service": "payjsapi", "base_url": BASE_URL}
if str(check_zpay).lower() in ("1", "true", "yes"):
try:
r = requests.get("https://zpayz.cn", timeout=5)
out["zpayz_reachable"] = r.status_code in (200, 301, 302, 404)
except Exception as e:
out["zpayz_reachable"] = False
out["zpayz_error"] = str(e)
return out
# 挂载路由 # 挂载路由
app.include_router(nomadvip_router) app.include_router(nomadvip_router)
app.include_router(digital_router) app.include_router(digital_router)

View File

@@ -115,7 +115,15 @@ class ZPayProvider(PaymentProvider):
params["sign_type"] = "MD5" params["sign_type"] = "MD5"
params["sign"] = self._md5_sign(params) params["sign"] = self._md5_sign(params)
resp = requests.post(self.MAPI_URL, data=params, timeout=15) try:
resp = requests.post(self.MAPI_URL, data=params, timeout=15)
except requests.RequestException as e:
return {
"status": "error",
"provider": self.name,
"msg": f"连接 zpayz.cn 失败: {e}。请检查服务器网络、防火墙或 DNS。",
}
try: try:
result = resp.json() result = resp.json()
except Exception: except Exception: