Angular集成Stripe结账时跳转出现CORS错误的问题
Angular + Stripe结账流程故障修复
问题描述
开发基础Angular应用,用户可选择3种套餐并通过Stripe完成结账。点击"Buy Now"按钮后无响应,控制台出现CORS相关错误,无法携带对应priceId跳转至Stripe结账页面。
错误原因
- 后端接口重定向方式错误:
/create-checkout-session接口直接通过res.redirect(303, session.url)跳转到Stripe结账页,但前端使用HttpClient发送AJAX请求,浏览器会拦截跨域重定向(Stripe域名未配置允许当前域名的CORS头)。 - 前后端流程不匹配:前端代码期望后端返回Stripe Session ID,再通过
stripeService.redirectToCheckout跳转,但后端直接返回重定向响应,导致前端无法获取有效Session数据。
修复方案
1. 修改后端server.js
将接口返回重定向改为返回Stripe Session的ID或URL,让前端自行处理跳转:
const stripe = require('stripe')('#Mykey#'); const express = require('express'); const app = express(); const cors = require('cors'); const PORT = 8080 const YOUR_DOMAIN = `http://localhost:${PORT}`; app.use(express.json()) app.use(cors({origin: ["http://localhost:8080", "https://checkout.stripe.com"],})); app.use(express.static('dist/payment-system')); app.get('/', async (req, res) => { res.sendFile('/index.html'); }); app.post('/create-checkout-session', async (req, res) => { const { priceId } = req.body; const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [ { price: priceId, quantity: 1, }, ], mode: 'payment', success_url: `${YOUR_DOMAIN}/success.html`, cancel_url: `${YOUR_DOMAIN}/cancel.html`, }); // 替换重定向,返回Session数据给前端 res.json({ sessionId: session.id, url: session.url }); }); app.listen(PORT, () => console.log(`Running on port ${PORT}`));
2. 修改前端otp-plans.component.ts
选择两种方式之一实现跳转:
方式一:使用ngx-stripe的redirectToCheckout(推荐)
import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { switchMap } from 'rxjs/operators'; import { StripeService } from 'ngx-stripe'; @Component({ selector: 'app-otp-plans', templateUrl: './otp-plans.component.html', styleUrls: ['./otp-plans.component.css'] }) export class OtpPlansComponent { constructor( private http: HttpClient, private stripeService: StripeService ) { } products = [ { name: 'Basic', price: 30.99, priceId: 'price_1N1IFtG68nNSlGgfGtVYENCJ', features: [ '1 user', '10 GB of storage', 'Help center access', 'Email support', ], }, { name: 'Premium', price: 129.99, priceId: 'price_1N1IIhG68nNSlGgf6URNg1iR', features: [ '10 users', '100 GB of storage', 'Help center access', 'Email support', 'Phone support', 'SSO via Google' ], }, { name: 'Ultimate', price: 579.99, priceId: 'price_1N1IJjG68nNSlGgfeY6tx2nk', features: [ 'Unlimited users', 'unlimited storage', 'Help center access', 'Email support', 'Phone support', 'Custom branding', 'Knowledge base', 'SSO via Google', ], }, ]; checkout(priceId: string) { this.http.post('/create-checkout-session', { priceId }) .pipe( switchMap((session: any) => { // 使用返回的sessionId调用Stripe跳转方法 return this.stripeService.redirectToCheckout({ sessionId: session.sessionId }) }) ) .subscribe(result => { if (result.error) { alert(result.error.message); } }); } }
方式二:直接通过URL跳转
如果不想依赖ngx-stripe的方法,也可以直接跳转到Stripe的结账URL:
// 修改checkout方法 checkout(priceId: string) { this.http.post('/create-checkout-session', { priceId }) .subscribe((session: any) => { window.location.href = session.url; }, error => { alert('创建结账会话失败:' + error.message); }); }
3. 前端HTML无需修改
otp-plans.component.html代码保持不变,按钮点击事件已正确传递priceId:
<div id="otp-plans-container"> <header> <h2>One-time-payment plans</h2> <p>Pay once, for lifetime use</p> </header> <main> <div *ngFor="let product of products" class="plan"> <div class="plan-header"> <h3>{{ product.name }}</h3> <p>€{{ product.price }}</p> </div> <div class="plan-body"> <ul> <li *ngFor="let feature of product.features" class="plan-included">{{ feature }}</li> </ul> </div> <div class="plan-footer"> <button (click)="checkout(product.priceId)">Buy Now</button> </div> </div> </main> </div>
验证修复
- 重启Node.js服务器
- 确保Angular应用构建产物已生成在
dist/payment-system目录 - 点击任意套餐的"Buy Now"按钮,将成功跳转至Stripe结账页面
内容的提问来源于stack exchange,提问作者Gill Mertens
相关产品推荐
相关产品推荐

