Stripe自定义表单集成报错:StripeCheckout未定义及支付参数缺失
解决Stripe自定义表单支付的一系列错误问题
看起来你在混用Stripe的不同版本API,加上合规性和配置问题导致了这一堆错误,我来一步步帮你理清并解决:
核心问题拆解
首先要明确两个关键错误根源:
- 你用了Stripe v3的JS SDK,却在调用v2的
StripeCheckout旧API,这直接导致StripeCheckout is not defined错误 - 直接收集信用卡号、有效期、CVC是违反Stripe PCI合规要求的,你不能自己写输入框处理这些敏感信息,必须用Stripe Elements来托管输入,否则不仅报错,还会触发合规风险
分步解决方案
1. 先修复Stripe密钥配置问题
首先确保你的Laravel配置是正确的:
- 在
.env文件里填入正确的Stripe密钥:STRIPE_KEY=pk_test_你的公钥 STRIPE_SECRET=sk_test_你的密钥 - 清除Laravel配置缓存(如果之前缓存过):
php artisan config:clear - 在JS里引用密钥时必须加引号,否则Laravel解析后会被JS当成变量:
const stripe = Stripe("{{ config('services.stripe.key') }}");
2. 替换自定义表单为Stripe Elements(合规且正确)
删掉你自己写的卡号、有效期、CVC输入框,改用Stripe Elements来生成安全的输入组件:
<form action="{{ route('registration.charge') }}" method="post" id="paymentForm"> {{ csrf_field() }} <input type="hidden" name="stripePaymentMethod" id="stripePaymentMethod"/> <!-- Stripe Elements 卡片输入容器 --> <div class="form-group font-size-sm"> <label class="text-gray">Card Number</label> <div id="card-element" class="form-control"></div> <!-- 错误提示区域 --> <div id="card-errors" role="alert" class="text-danger mt-1"></div> </div> <input type="submit" id="confirmPayment" class="btn btn-primary" value="Confirm"/> </form>
3. 修正前端JS代码(使用v3正确API)
替换原来的JS,用Stripe Elements处理卡片输入和支付流程:
<script src="https://js.stripe.com/v3/"></script> <script> // 初始化Stripe const stripe = Stripe("{{ config('services.stripe.key') }}"); const elements = stripe.elements(); // 自定义Elements输入框样式(可选,匹配你的网站风格) const style = { base: { color: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } }; // 创建卡片输入组件并挂载到页面 const cardElement = elements.create('card', {style: style}); cardElement.mount('#card-element'); // 监听卡片输入错误 cardElement.addEventListener('change', function(event) { const errorElement = document.getElementById('card-errors'); if (event.error) { errorElement.textContent = event.error.message; } else { errorElement.textContent = ''; } }); // 处理表单提交 const form = document.getElementById('paymentForm'); form.addEventListener('submit', async function(event) { event.preventDefault(); // 创建PaymentMethod(替代旧的stripeToken) const { paymentMethod, error } = await stripe.createPaymentMethod({ type: 'card', card: cardElement, }); if (error) { // 显示卡片错误信息 document.getElementById('card-errors').textContent = error.message; } else { // 将PaymentMethod ID存入隐藏字段,提交表单到后端 document.getElementById('stripePaymentMethod').value = paymentMethod.id; form.submit(); } }); </script>
4. 修正后端Charge代码(使用PaymentMethod)
Stripe v3推荐用PaymentMethod替代旧的token,修改你的charge方法:
use Stripe\Customer; use Stripe\Charge; use Stripe\Exception\CardException; public function charge(Request $request) { Stripe::setApiKey(config('services.stripe.secret')); try { // 获取前端传递的PaymentMethod ID $paymentMethodId = $request->stripePaymentMethod; // 创建Customer(推荐,方便后续重复扣款) $customer = Customer::create([ 'payment_method' => $paymentMethodId, 'email' => auth()->user()->email, // 替换为实际用户邮箱 'invoice_settings' => [ 'default_payment_method' => $paymentMethodId, ], ]); // 创建扣款订单 $charge = Charge::create([ 'currency' => 'eur', 'amount' => 1000, // 单位是分,1000=10欧元 'customer' => $customer->id, // 使用Customer ID而非直接传入source ]); // 支付成功后的逻辑,比如跳转成功页面 return redirect()->route('payment.success')->with('success', 'Payment completed!'); } catch (CardException $e) { // 卡片相关错误(余额不足、过期等) return back()->withErrors($e->getError()->message); } catch (\Exception $e) { // 其他通用错误 return back()->withErrors('Payment failed, please try again later.'); } }
错误逐个解决说明
Must provide source or customer:现在后端用Customer ID替代了空的stripeToken,满足Stripe API要求Uncaught ReferenceError: StripeCheckout is not defined:改用了v3的Elements API,不再依赖旧的StripeCheckout对象Uncaught ReferenceError: pk_test_.... is not defined:密钥被包裹在引号里,Laravel解析后是合法的字符串,不会被JS当成变量Invalid value for Stripe(): apiKey should be a string:确保.env配置正确并清除缓存后,config('services.stripe.key')会返回正确的字符串密钥
内容的提问来源于stack exchange,提问作者johnW
相关产品推荐
相关产品推荐

