Explorar el Código

fix: 支付宝沙箱支付集成 - 私钥格式修复 + wap.pay 接口切换

- 修复 dotenv 多行 PEM 解析问题,自动添加 RSA PRIVATE KEY 头尾
- 切换为 alipay.trade.wap.pay 接口,提取完整签名 URL 返回前端
- 修复沙箱网关地址

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MyFramework User hace 3 meses
padre
commit
b67b1f6caa
Se han modificado 1 ficheros con 28 adiciones y 17 borrados
  1. 28 17
      server/src/modules/payment/payment.service.ts

+ 28 - 17
server/src/modules/payment/payment.service.ts

@@ -44,9 +44,14 @@ function getAlipaySdk(): any | null {
     console.warn('[Alipay] 支付宝 SDK 未加载');
     return null;
   }
-  const appId = process.env.ALIPAY_APP_ID;
-  const privateKey = process.env.ALIPAY_PRIVATE_KEY;
-  const alipayPublicKey = process.env.ALIPAY_PUBLIC_KEY;
+  const appId = process.env.ALIPAY_APP_ID || '';
+  // dotenv 不解析多行 PEM,手动加 PEM 头尾
+  const rawPrivateKey = process.env.ALIPAY_PRIVATE_KEY || '';
+  const privateKey = rawPrivateKey.includes('BEGIN') ? rawPrivateKey
+    : `-----BEGIN RSA PRIVATE KEY-----\n${rawPrivateKey}\n-----END RSA PRIVATE KEY-----`;
+  const rawPublicKey = process.env.ALIPAY_PUBLIC_KEY || '';
+  const alipayPublicKey = rawPublicKey.includes('BEGIN') ? rawPublicKey
+    : `-----BEGIN PUBLIC KEY-----\n${rawPublicKey}\n-----END PUBLIC KEY-----`;
 
   if (!appId || !privateKey || !alipayPublicKey) {
     console.warn('[Alipay] 未配置支付宝参数');
@@ -58,7 +63,7 @@ function getAlipaySdk(): any | null {
       appId,
       privateKey,
       alipayPublicKey,
-      gateway: 'https://openapi.alipay.com/gateway.do',
+      gateway: 'https://openapi-sandbox.dl.alipaydev.com/gateway.do',
     });
   }
 
@@ -216,26 +221,32 @@ async function generateAlipayPayment(
   const useSandbox = !isProduction;
 
   try {
-    // 使用电脑网站支付 API - pageExecute 返回表单 HTML 或 GET URL
+    // 使用电脑网站支付 API
     const bizContent = {
-      outTradeNo: orderNo,
-      productCode: 'FAST_INSTANT_TRADE_PAY',
-      totalAmount: amount,
+      out_trade_no: orderNo,
+      total_amount: String(amount),
       subject: subject,
-      body: `订阅${subject}会员`,
+      product_code: 'FAST_INSTANT_TRADE_PAY',
+      quit_url: finalReturnUrl,
     };
 
-    // 使用 pageExecute - 返回已签名的 URL 或表单
-    const paymentUrl = sdk.pageExecute(
-      'alipay.trade.page.pay',
-      'GET',
-      bizContent
-    );
+    // 使用 wap.pay 返回表单,提取 action URL 用于跳转
+    const htmlForm = sdk.pageExec('alipay.trade.wap.pay', {
+      bizContent: {
+        out_trade_no: orderNo,
+        total_amount: String(amount),
+        subject: subject,
+        quit_url: finalReturnUrl,
+      },
+      useSandbox: true,
+    });
 
-    console.log('[Alipay] 支付链接生成成功, paymentUrl:', paymentUrl);
+    // 从 HTML 表单中提取 action URL
+    const actionMatch = String(htmlForm).match(/action="([^"]+)"/);
+    const paymentUrl = actionMatch ? actionMatch[1] : '';
 
     return {
-      paymentUrl: paymentUrl,
+      paymentUrl,
     };
   } catch (error) {
     console.error('[Alipay] 支付链接生成失败:', error);