You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更新Stripe Price(payment_intent)以匹配所选订阅时长?

解决Stripe订阅价格动态更新问题(无表单提交)

核心思路

放弃iframe方案,改用AJAX异步请求将选中的订阅时长传给后端PHP,后端返回对应Stripe价格配置,前端再初始化支付模态框,全程无需刷新页面。

具体实现步骤

1. 前端HTML与JavaScript逻辑

监听下拉菜单变化,异步获取对应价格ID,点击支付按钮后初始化Stripe卡片元素并弹出模态框:

<!-- 订阅时长下拉菜单 -->
<select id="subscription-duration">
  <option value="1">1个月</option>
  <option value="3">3个月</option>
  <option value="6">6个月</option>
  <option value="12">12个月</option>
</select>

<!-- 触发支付模态框的按钮 -->
<button id="checkout-btn">确认订阅</button>

<!-- Stripe支付模态框(默认隐藏) -->
<div id="stripe-modal" style="display:none;">
  <div id="card-element"></div>
  <button id="pay-btn">完成支付</button>
</div>

<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('你的Stripe公钥');
const elements = stripe.elements();
let currentPriceId = ''; // 存储当前选中的订阅价格ID

// 监听下拉菜单选择变化
document.getElementById('subscription-duration').addEventListener('change', async function() {
  const duration = this.value;
  // 异步请求后端获取对应价格ID
  const response = await fetch('get-price.php', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `duration=${duration}`
  });
  const data = await response.json();
  currentPriceId = data.price_id;
});

// 点击支付按钮,初始化卡片元素并显示模态框
document.getElementById('checkout-btn').addEventListener('click', function() {
  if (!currentPriceId) {
    alert('请先选择订阅时长');
    return;
  }
  const cardElement = elements.create('card');
  cardElement.mount('#card-element');
  document.getElementById('stripe-modal').style.display = 'block';
});

// 提交支付请求
document.getElementById('pay-btn').addEventListener('click', async function() {
  // 先调用后端创建订阅/支付意图
  const createResponse = await fetch('create.php', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `price_id=${currentPriceId}`
  });
  const createData = await createResponse.json();

  // 确认卡片支付
  const { error } = await stripe.confirmCardPayment(createData.client_secret, {
    payment_method: {
      card: cardElement,
      billing_details: {name: '用户姓名'} // 可替换为用户输入的姓名
    }
  });

  if (error) {
    console.error(error.message);
  } else {
    alert('订阅成功');
    document.getElementById('stripe-modal').style.display = 'none';
  }
});
</script>

2. 后端get-price.php(映射时长到Stripe价格ID)

根据前端传递的订阅时长,返回预定义的Stripe价格ID(需提前在Stripe后台创建对应订阅价格):

<?php
$duration = $_POST['duration'] ?? '';

// 定义各订阅时长对应的Stripe价格ID
$priceMap = [
  '1' => 'price_xxxxxx', // 1个月订阅价格ID
  '3' => 'price_yyyyyy', // 3个月订阅价格ID
  '6' => 'price_zzzzzz', // 6个月订阅价格ID
  '12' => 'price_aaaaaa' // 12个月订阅价格ID
];

if (isset($priceMap[$duration])) {
  echo json_encode(['price_id' => $priceMap[$duration]]);
} else {
  echo json_encode(['error' => '无效的订阅时长']);
}
?>

3. 后端create.php(创建Stripe订阅/支付意图)

接收前端传递的价格ID,创建Stripe订阅对象并返回客户端密钥:

<?php
require_once 'vendor/autoload.php';
\Stripe\Stripe::setApiKey('你的Stripe私钥');

$priceId = $_POST['price_id'] ?? '';
if (!$priceId) {
  http_response_code(400);
  echo json_encode(['error' => '缺少价格ID']);
  exit;
}

try {
  // 创建订阅(替换cus_xxxxxx为实际用户的Customer ID,或先创建新Customer)
  $subscription = \Stripe\Subscription::create([
    'customer' => 'cus_xxxxxx',
    'items' => [['price' => $priceId]],
    'payment_behavior' => 'default_incomplete',
    'payment_settings' => ['save_payment_method' => 'on_subscription'],
    'expand' => ['latest_invoice.payment_intent'],
  ]);

  echo json_encode([
    'client_secret' => $subscription->latest_invoice->payment_intent->client_secret
  ]);
} catch (\Stripe\Exception\ApiErrorException $e) {
  http_response_code(500);
  echo json_encode(['error' => $e->getMessage()]);
}
?>

关键说明

  • AJAX方案避免了iframe的上下文隔离问题,变量传递更直接可靠。
  • 前端提前通过下拉变化获取价格ID,无需等待表单提交再处理价格逻辑。
  • 后端拆分get-price.php和create.php,职责更清晰,便于维护。

内容的提问来源于stack exchange,提问作者cleanlock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 05:25:16