|
@@ -44,9 +44,14 @@ function getAlipaySdk(): any | null {
|
|
|
console.warn('[Alipay] 支付宝 SDK 未加载');
|
|
console.warn('[Alipay] 支付宝 SDK 未加载');
|
|
|
return null;
|
|
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) {
|
|
if (!appId || !privateKey || !alipayPublicKey) {
|
|
|
console.warn('[Alipay] 未配置支付宝参数');
|
|
console.warn('[Alipay] 未配置支付宝参数');
|
|
@@ -58,7 +63,7 @@ function getAlipaySdk(): any | null {
|
|
|
appId,
|
|
appId,
|
|
|
privateKey,
|
|
privateKey,
|
|
|
alipayPublicKey,
|
|
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;
|
|
const useSandbox = !isProduction;
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- // 使用电脑网站支付 API - pageExecute 返回表单 HTML 或 GET URL
|
|
|
|
|
|
|
+ // 使用电脑网站支付 API
|
|
|
const bizContent = {
|
|
const bizContent = {
|
|
|
- outTradeNo: orderNo,
|
|
|
|
|
- productCode: 'FAST_INSTANT_TRADE_PAY',
|
|
|
|
|
- totalAmount: amount,
|
|
|
|
|
|
|
+ out_trade_no: orderNo,
|
|
|
|
|
+ total_amount: String(amount),
|
|
|
subject: subject,
|
|
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 {
|
|
return {
|
|
|
- paymentUrl: paymentUrl,
|
|
|
|
|
|
|
+ paymentUrl,
|
|
|
};
|
|
};
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('[Alipay] 支付链接生成失败:', error);
|
|
console.error('[Alipay] 支付链接生成失败:', error);
|