From ddbf30652ca2fa060e53ccfb139481140d316f34 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 10 Mar 2026 07:05:35 -0500 Subject: [PATCH] 's' --- .env.example | 8 ++++++-- README.md | 10 ++++++++++ app/main.py | 36 +++++++++++++++++++++++++++++++++++- app/payment/zpay.py | 10 +++++++++- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index a34f803..de04868 100644 --- a/.env.example +++ b/.env.example @@ -6,8 +6,12 @@ # 本地调试:ngrok 暴露 8700 后设置 BASE_URL=https://xxx.ngrok.io # 线上部署:BASE_URL=https://api.hackrobot.cn -# ========== 生产部署 ========== -# BASE_URL 必须为 payjsapi 实际公网地址,ZPAY 异步通知会请求此地址 +# ========== 生产部署(Ubuntu 等)========== +# 线上部署必须正确配置,否则会显示「支付失败」: +# 1. BASE_URL 必须为 payjsapi 公网地址,ZPAY 需能访问此地址做异步回调 +# 错误示例:http://127.0.0.1:8700、http://localhost(ZPAY 无法访问) +# 正确示例:https://api.hackrobot.cn(域名需解析到本机并配置 nginx 反向代理) +# 2. 服务器需能访问 zpayz.cn(检查防火墙、DNS),可访问 /health?check_zpay=1 自检 BASE_URL=https://api.hackrobot.cn # 支付渠道:zpay(已替代 xorpay)| xorpay diff --git a/README.md b/README.md index 3165fef..4b8228b 100755 --- a/README.md +++ b/README.md @@ -82,6 +82,16 @@ PAYMENT_PROVIDER=zpay # 其他 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 To make it easy for you to get started with GitLab, here's a list of recommended next steps. diff --git a/app/main.py b/app/main.py index 3c79f1c..b909e0d 100755 --- a/app/main.py +++ b/app/main.py @@ -11,14 +11,16 @@ - common: /submit_meetup_application、/create_user 本地调试:BASE_URL 需为 ZPAY 可访问地址(如 ngrok) -线上部署:https://api.hackrobot.cn +线上部署:BASE_URL=https://api.hackrobot.cn(必须为 ZPAY 可公网访问的地址) """ import logging +import requests from fastapi import FastAPI, Request, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse +from .config import BASE_URL from .routers import ( nomadvip_router, digital_router, @@ -58,6 +60,38 @@ logging.basicConfig( 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(digital_router) diff --git a/app/payment/zpay.py b/app/payment/zpay.py index d007fc4..7809440 100644 --- a/app/payment/zpay.py +++ b/app/payment/zpay.py @@ -115,7 +115,15 @@ class ZPayProvider(PaymentProvider): params["sign_type"] = "MD5" 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: result = resp.json() except Exception: