's'
This commit is contained in:
@@ -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://localhost(ZPAY 无法访问)
|
||||||
|
# 正确示例: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
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -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.
|
||||||
|
|||||||
36
app/main.py
36
app/main.py
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user