diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d56eaf4 --- /dev/null +++ b/.env.example @@ -0,0 +1,35 @@ +# ========== 与 payjsapi/digital/cnomadcna 同源 ========== +# 复制为 .env.local,PB/Memos 与 payjsapi 保持一致 + +# ========== PocketBase ========== +NEXT_PUBLIC_POCKETBASE_URL=https://pocketbase.hackrobot.cn +POCKETBASE_EMAIL=xiaoshuang.eric@gmail.com +POCKETBASE_PASSWORD=Xiao4669805@ + +# ========== 支付(payjsapi)========== +# 本地开发:127.0.0.1 表示本机 +# 生产同机部署:设 PAYMENT_API_INTERNAL_URL 避免服务器访问自身公网 IP 失败(hairpin NAT) +PAYMENT_API_URL=http://127.0.0.1:8007 +NEXT_PUBLIC_API_URL=http://127.0.0.1:8007 +# 生产同机部署时取消注释(Next.js 与 payjsapi 同服务器) +# PAYMENT_API_INTERNAL_URL=http://127.0.0.1:8007 +PAYMENT_PROVIDER=zpay +PAYMENT_DEFAULT_AMOUNT=100 +NEXT_PUBLIC_SITE_ID=vip +ZPAY_SUBMIT_URL=https://zpayz.cn/submit.php + +# ========== Memos(pay/confirm 创建账号,与 payjsapi MEMOS_TOKEN 同值)========== +MEMOS_API_URL=https://qun.hackrobot.cn +MEMOS_ACCESS_TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiaGFja3JvYm90IiwiaXNzIjoibWVtb3MiLCJzdWIiOiIxIiwiYXVkIjpbInVzZXIuYWNjZXNzLXRva2VuIl0sImlhdCI6MTc1NzQwNTE0OX0.Idn7kBlxE-CoSOXwWuZ1tHGIRKHAIeDyXSafGS5OHsg + +# ========== MinIO ========== +MINIO_ENDPOINT=minioweb.hackrobot.cn +MINIO_PORT=9035 +MINIO_USE_SSL=false +MINIO_BUCKET=hackrobot +MINIO_PUBLIC_URL=https://minioweb.hackrobot.cn/hackrobot + +# 如需上传需配置(服务端) +# MINIO_ACCESS_KEY= +# MINIO_SECRET_KEY= +# MINIO_REGION=china diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..2648153 --- /dev/null +++ b/.env.local @@ -0,0 +1,13 @@ +# 本地调试 - 支付测试 1 元、zpay 渠道 +NEXT_PUBLIC_POCKETBASE_URL=https://pocketbase.hackrobot.cn +PAYMENT_API_URL=http://127.0.0.1:8007 +PAYMENT_PROVIDER=zpay +PAYMENT_DEFAULT_AMOUNT=100 +NEXT_PUBLIC_SITE_ID=vip +NEXT_PUBLIC_API_URL=http://127.0.0.1:8007 + +# 与 payjsapi 同源(pay/confirm 写入 payments/site_vip、创建 Memos) +POCKETBASE_EMAIL=xiaoshuang.eric@gmail.com +POCKETBASE_PASSWORD=Xiao4669805@ +MEMOS_API_URL=https://qun.hackrobot.cn +MEMOS_ACCESS_TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiaGFja3JvYm90IiwiaXNzIjoibWVtb3MiLCJzdWIiOiIxIiwiYXVkIjpbInVzZXIuYWNjZXNzLXRva2VuIl0sImlhdCI6MTc1NzQwNTE0OX0.Idn7kBlxE-CoSOXwWuZ1tHGIRKHAIeDyXSafGS5OHsg diff --git a/.gitignore b/.gitignore index 5ef6a52..1b7a73a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,7 @@ yarn-error.log* .pnpm-debug.log* # env files (can opt-in for committing if needed) -.env* +# .env* # vercel .vercel diff --git a/app/api/pay/route.ts b/app/api/pay/route.ts index 9676220..34bc339 100644 --- a/app/api/pay/route.ts +++ b/app/api/pay/route.ts @@ -130,12 +130,10 @@ export async function POST(request: NextRequest) { const payConfig = getPaymentConfig(); const hostHeader = request.headers.get("host") || request.headers.get("x-forwarded-host"); - // 优先用请求 Host(等同 window.location.host)推断同机 payjsapi,访问 192.168.41.222:3002 即用 192.168.41.222:8007 const apiUrl = ( (hostHeader ? getApiUrlFromRequest(hostHeader) : null) || payConfig.apiUrl - ) - .replace(/\/$/, ""); + ).replace(/\/$/, ""); console.log("[pay] 立即加入 apiUrl=%s host=%s", apiUrl, hostHeader); let user_id = String(body?.user_id || "").trim(); if (user_id.startsWith("{") && user_id.includes("data")) { diff --git a/config/services.config.ts b/config/services.config.ts index 4b5b319..8444509 100644 --- a/config/services.config.ts +++ b/config/services.config.ts @@ -42,17 +42,24 @@ export function getPocketBaseConfig(): PocketBaseConfig { const PAYJSAPI_PORT = process.env.PAYJSAPI_PORT || "8007"; /** - * 根据请求 Host 推断 payjsapi 地址(同主机:8007) + * 根据请求 Host 推断 payjsapi 地址。同机部署时优先用 PAYMENT_API_INTERNAL_URL。 * 访问 192.168.41.222:3000 时自动用 192.168.41.222:8007 */ export function getApiUrlFromRequest(hostHeader: string | null): string { + const internal = process.env.PAYMENT_API_INTERNAL_URL?.trim(); + if (internal) return internal.replace(/\/$/, ""); if (!hostHeader) return isDev ? `http://127.0.0.1:${PAYJSAPI_PORT}` : "https://api.hackrobot.cn"; const hostname = hostHeader.split(":")[0]; return isDev ? `http://${hostname}:${PAYJSAPI_PORT}` : "https://api.hackrobot.cn"; } -/** 生产环境若 PAYMENT_API_URL 指向 localhost,则忽略并使用 api 域名 */ +/** + * 支付 API 地址。同机部署时优先用 PAYMENT_API_INTERNAL_URL 避免 hairpin NAT 问题。 + * 生产环境若 PAYMENT_API_URL 指向 localhost 且未设 INTERNAL,则用 api 域名。 + */ function resolvePaymentApiUrl(): string { + const internal = process.env.PAYMENT_API_INTERNAL_URL?.trim(); + if (internal) return internal.replace(/\/$/, ""); const url = process.env.PAYMENT_API_URL || process.env.NEXT_PUBLIC_API_URL ||