62 lines
2.3 KiB
TypeScript
62 lines
2.3 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
||
import { getApiUrlFromRequest, getPaymentConfig } from "@/config/services.config";
|
||
import { queryXorPayOrderStatus } from "@/app/lib/xorpayStatus";
|
||
import { queryZPayOrderStatus } from "@/app/lib/zpayStatus";
|
||
|
||
function resolvePayApiUrl(request: NextRequest): string {
|
||
const config = getPaymentConfig();
|
||
const hostHeader =
|
||
request.headers.get("host") || request.headers.get("x-forwarded-host");
|
||
return (getApiUrlFromRequest(hostHeader) || config.apiUrl).replace(/\/$/, "");
|
||
}
|
||
|
||
/**
|
||
* 支付状态查询:salonapi 优先,失败时直接向 zpay/xorpay 查询兜底
|
||
* 参考 nomadvip,保证本地无回调时也能检测到支付
|
||
*/
|
||
export async function GET(request: NextRequest) {
|
||
const orderId = request.nextUrl.searchParams.get("order_id");
|
||
if (!orderId) {
|
||
return NextResponse.json(
|
||
{ ok: false, error: "missing order_id" },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
const hostHeader =
|
||
request.headers.get("host") || request.headers.get("x-forwarded-host");
|
||
const apiUrl = resolvePayApiUrl(request);
|
||
const salonUrl = `${apiUrl}/salon/order_status?order_id=${encodeURIComponent(orderId)}`;
|
||
|
||
// 并行查询 salonapi、xorpay、zpay,任一返回 paid 即立即返回,避免串行阻塞
|
||
const salonPaid = (async () => {
|
||
try {
|
||
const controller = new AbortController();
|
||
const timeout = setTimeout(() => controller.abort(), 3000);
|
||
const res = await fetch(salonUrl, {
|
||
cache: "no-store",
|
||
signal: controller.signal,
|
||
}).finally(() => clearTimeout(timeout));
|
||
const data = await res.json().catch(() => ({}));
|
||
return !!data?.paid;
|
||
} catch (error) {
|
||
console.warn(
|
||
"[pay/status] salonapi order_id=%s url=%s error=%s",
|
||
orderId,
|
||
salonUrl,
|
||
error instanceof Error ? error.message : String(error)
|
||
);
|
||
return false;
|
||
}
|
||
})();
|
||
|
||
const xorpayPaid = queryXorPayOrderStatus(orderId, 5000).then((r) => r?.paid ?? false);
|
||
const zpayPaid = queryZPayOrderStatus(orderId, 5000).then((r) => r?.paid ?? false);
|
||
|
||
const [salon, xorpay, zpay] = await Promise.all([salonPaid, xorpayPaid, zpayPaid]);
|
||
if (salon || xorpay || zpay) {
|
||
return NextResponse.json({ ok: true, paid: true });
|
||
}
|
||
return NextResponse.json({ ok: true, paid: false });
|
||
}
|