Angular/TypeScript集成Stripe支付页面初始化及提交报错求助
错误详情
1. 初始化阶段错误
Uncaught TypeError: Cannot read properties of undefined (reading 'queuedMessages')
at value (https://js.stripe.com/v3/fingerprinted/js/controller-803e2f3ecfca23afd889cd24f93bdf22.js:1:452741)
at (https://js.stripe.com/v3/fingerprinted/js/controller-803e2f3ecfca23afd889cd24f93bdf22.js:1:451881)
value @ js.stripe.com/v3/fingerprinted/js/controller-803e2f3ecfca23afd889cd24f93bdf22.js:1:452741
2. 提交阶段错误
ERROR IntegrationError: 请使用创建此Element时所用的同一
Stripe实例来创建Source或Token。
at Ii (/Users/mysite/client:1:350323)
at e._handleMessage (/Users/mysite/client:1:355676)
at e._handleMessage (/Users/mysite/client:1:152157)
at /Users/mysite/client:1:353245
at _ZoneDelegate.invokeTask (/Users/mysite/client/node_modules/zone.js/fesm2015/zone.js:406:1)
at Object.onInvokeTask (/Users/mysite/client/node_modules/@angular/core/fesm2015/core.mjs:25535:1)
at _ZoneDelegate.invokeTask (/Users/mysite/client/node_modules/zone.js/fesm2015/zone.js:405:1)
at Zone.runTask (/Users/mysite/client/node_modules/zone.js/fesm2015/zone.js:178:1)
at ZoneTask.invokeTask [as invoke] (/Users/mysite/client/node_modules/zone.js/fesm2015/zone.js:487:1)
at invokeTask (https://localhost:4200/polyfills.js:4776:18) {message: '请使用创建此Element时所用的同一Stripe实例来创建Source或Token。', name: 'IntegrationError', stack: 'IntegrationError: 请使用创建此Element时所用的同一Stripe实例来创建Source或Token。\n at Ii (...'}
问题分析
- 初始化错误:Stripe脚本未完全加载就执行初始化代码,或存在重复加载Stripe脚本的情况,导致全局对象状态异常。
- 提交错误:调用
createToken时使用的Stripe实例与创建Card Element时的实例不一致。可能是组件重新渲染时重复创建实例,或变量作用域问题导致实例被覆盖。
代码还存在其他潜在问题:
- 直接
declare const Stripe: any缺乏类型支持,无法保证脚本加载时机 ngAfterViewInit中有多余的});语法错误- 事件监听函数未绑定组件上下文,导致
this指向异常
解决方案
步骤1:规范Stripe依赖引入
使用官方@stripe/stripe-js包管理Stripe加载与实例化,确保脚本就绪后再初始化:
npm install @stripe/stripe-js
组件中导入并预加载Stripe:
import { loadStripe } from '@stripe/stripe-js'; // 组件类内定义 private stripePromise: Promise<Stripe | null>; ngOnInit() { // 提前加载Stripe,避免初始化时脚本未就绪 this.stripePromise = loadStripe('pk_test_fTrh6B1...'); }
步骤2:确保Stripe实例单例化
在ngAfterViewInit中等待Stripe加载完成后,仅初始化一次实例:
async ngAfterViewInit() { const style = { // 你的样式配置 }; this.stripe = await this.stripePromise; if (!this.stripe) return; this.stripeElements = this.stripe.elements(); // 创建并挂载Card Number Element this.cardNumber = this.stripeElements.create('cardNumber', { style }); this.cardNumber.mount(this.cardNumberElement.nativeElement); // 绑定组件上下文,避免this指向异常 this.cardNumber.addEventListener('change', (event) => this.cardNumberHandler(event)); // 创建并挂载Card Expiry Element this.cardExpiry = this.stripeElements.create('cardExpiry', { style }); this.cardExpiry.mount(this.cardExpiryElement.nativeElement); this.cardExpiry.addEventListener('change', (event) => this.cardExpiryHandler(event)); // 创建并挂载Card CVC Element this.cardCvc = this.stripeElements.create('cardCvc', { style }); this.cardCvc.mount(this.cardCvcElement.nativeElement); this.cardCvc.addEventListener('change', (event) => this.cardCvcHandler(event)); }
步骤3:修正提交逻辑
确保createToken使用初始化时的同一Stripe实例:
submitCard() { if (!this.stripe || !this.cardNumber) return; this.loadingPayment = true; const cardData = { name: this.nameOnCard.value }; from(this.stripe.createToken(this.cardNumber, cardData)).pipe(take(1)).subscribe((result: any) => { this.loadingPayment = false; if (result.error) { this.alertService.danger(result.error.message); return; } const allowedBrands = ['Visa', 'MasterCard', 'Discover', 'American Express']; if (allowedBrands.includes(result.token.card.brand)) { this.accountService.saveCard({ token: result.token.id }).subscribe({ next: () => { this.router.navigate(['/account/cards']); this.alertService.success('卡片添加成功'); }, error: (err) => console.log(err) }); } else { this.alertService.info('仅接受Visa、MasterCard、Discover或American Express卡'); } }); }
步骤4:修正HTML模板拼写错误
将模板中Expirtion改为正确的Expiration:
<label for="floatingExpiration">Expiration</label>
关键注意事项
- 组件生命周期内仅初始化一次Stripe实例,禁止重复创建
- 调用
createToken/createPaymentMethod时,必须使用创建Element的同一Stripe实例 - 确保Stripe脚本加载完成后再执行初始化逻辑,避免因脚本未就绪导致的异常
内容的提问来源于stack exchange,提问作者chuckd

