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

Angular集成Stripe结账时跳转出现CORS错误的问题

Angular + Stripe结账流程故障修复

问题描述

开发基础Angular应用,用户可选择3种套餐并通过Stripe完成结账。点击"Buy Now"按钮后无响应,控制台出现CORS相关错误,无法携带对应priceId跳转至Stripe结账页面。

错误原因

  1. 后端接口重定向方式错误:/create-checkout-session接口直接通过res.redirect(303, session.url)跳转到Stripe结账页,但前端使用HttpClient发送AJAX请求,浏览器会拦截跨域重定向(Stripe域名未配置允许当前域名的CORS头)。
  2. 前后端流程不匹配:前端代码期望后端返回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>

验证修复

  1. 重启Node.js服务器
  2. 确保Angular应用构建产物已生成在dist/payment-system目录
  3. 点击任意套餐的"Buy Now"按钮,将成功跳转至Stripe结账页面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 17:59:58