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

Angular集成Stripe支付遭遇CORS跨域问题求助

Angular+Node.js集成Stripe支付时的CORS错误解决

Access to XMLHttpRequest at 'https://checkout.stripe.com/c/pay/cs_test_a1GABMpi' (redirected from 'http://localhost:5000/create-checkout-session') from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

问题场景

在Angular前端和Node.js后端集成Stripe支付时出现上述CORS错误,以下是前后端代码:

后端(Node.js)

const express = require('express');
const dotenv = require('dotenv');
const cors = require('cors');
const colors = require('colors');
const connectDB = require('./config/db');
const morgan = require('morgan');
const errorHandler = require('./middleware/error');
dotenv.config({ path: './config/config.env' });
const stripe = require('stripe')(process.env.STRIPE_API_KEY);

connectDB();

const app = express();
app.use(express.json());
app.use(express.static('public'));


app.use(
  cors({
    origin: '*',
  })
);

app.post('/create-checkout-session', async (req, res) => {
  console.log(process.env.STRIPE_API_KEY);
  const session = await stripe.checkout.sessions.create({
    line_items: [
      {
        price: process.env.STRIPE_PRICE,
        quantity: 1,
      },
    ],
    mode: 'payment',
    success_url: `https://google.com`,
    cancel_url: `https://google.com`,
    automatic_tax: { enabled: true },
  });

  res.redirect(303, session.url);
});

const PORT = process.env.PORT || 5000;

const server = app.listen(PORT, () => {
  console.log(
    `Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
  );
});

前端(Angular)

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class PaymentService {
  constructor(private http: HttpClient) {}

  startPayment() {
    const headers = new HttpHeaders({
      'Content-Type': 'text/html',
    });

    this.http
      .post('http://localhost:5000/create-checkout-session', {}, { headers })
      .subscribe((res) => console.log(res));
  }
}

问题分析

  1. 后端重定向逻辑错误:后端用res.redirect直接跳转到Stripe的结账URL,但前端是通过XMLHttpRequest(Angular HttpClient)发起的请求,重定向后会请求Stripe的域名,而Stripe服务器没有配置允许http://localhost:4200的CORS权限,导致报错。
  2. 前端请求头设置错误:手动设置Content-Type: text/html,但后端用express.json()解析JSON格式的请求,这个头会导致后端无法正确处理请求,同时也不符合接口的实际需求。

解决方案

修改后端代码

将接口改为返回Stripe会话URL的JSON响应,而非直接重定向:

app.post('/create-checkout-session', async (req, res) => {
  console.log(process.env.STRIPE_API_KEY);
  try {
    const session = await stripe.checkout.sessions.create({
      line_items: [
        {
          price: process.env.STRIPE_PRICE,
          quantity: 1,
        },
      ],
      mode: 'payment',
      success_url: `http://localhost:4200/success`, // 替换为你的前端成功页面
      cancel_url: `http://localhost:4200/cancel`, // 替换为你的前端取消页面
      automatic_tax: { enabled: true },
    });

    // 返回会话URL给前端,由前端跳转
    res.json({ url: session.url });
  } catch (error) {
    // 捕获错误并返回给前端
    res.status(500).json({ error: error.message });
  }
});

修改前端代码

移除错误的请求头,获取后端返回的URL后直接跳转至Stripe结账页面:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class PaymentService {
  constructor(private http: HttpClient) {}

  startPayment() {
    this.http
      .post<{ url: string }>('http://localhost:5000/create-checkout-session', {})
      .subscribe({
        next: (res) => {
          // 跳转到Stripe的结账页面
          window.location.href = res.url;
        },
        error: (err) => {
          console.error('创建支付会话失败:', err);
        },
      });
  }
}

额外优化建议

  • CORS配置收紧:将后端的cors({origin: '*'})改为指定允许的域名,比如origin: 'http://localhost:4200',生产环境替换为你的正式域名,提升安全性。
  • 错误处理:前后端都增加错误捕获逻辑,便于排查问题。

内容的提问来源于stack exchange,提问作者Bartłomiej Wydrzycki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:40:36