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

Stripe集成出现网络错误与CORS问题求助

Stripe集成出现网络错误与CORS问题求助

看起来你碰到了浏览器同源策略导致的CORS跨域拦截问题——虽然Postman和curl不受浏览器的CORS限制能正常调用API,但前端页面的请求被浏览器直接拦下来了,我来帮你梳理下排查和解决的方向。

先看浏览器给出的核心提示,已经把问题点得很明确了:

Ensure CORS response header values are valid
A cross-origin resource sharing (CORS) request was blocked because of invalid or missing response headers of the request or the associated preflight request.

create-checkout-session blocked

create-checkout-session Access-Control-Allow-Origin Missing Header

这说明你的后端在处理前端的跨域请求时,没有返回符合要求的Access-Control-Allow-Origin响应头,哪怕你已经引入了cors中间件,可能是配置不够精确导致的。

优先尝试的解决方案

1. 精确配置CORS中间件

你当前用的是默认的app.use(cors()),它会允许所有请求源(用*),但在浏览器的严格模式下,或者当请求涉及自定义头、凭证时,*可能无法被正确识别。建议改成明确指定你的前端服务地址:

// 替换原来的 app.use(cors())
app.use(cors({
  origin: 'http://localhost:3001', // 你的前端运行地址
  credentials: true, // 如果后续需要携带用户凭证(比如cookie)请开启,暂时不需要也可以设为false
  allowedHeaders: ['Content-Type'], // 和前端请求头保持一致
  methods: ['GET', 'POST', 'OPTIONS'] // 明确允许的请求方法,包含预请求的OPTIONS
}));

修改后重启后端服务,再用前端页面测试,这是解决这类问题最常见的有效手段。

2. 验证预请求(OPTIONS)是否正常

浏览器在发送跨域POST请求前,会先发送一个OPTIONS预请求确认权限,你可以用curl手动测试这个请求,看返回的响应头是否包含正确的CORS信息:

curl -X OPTIONS http://localhost:5001/api/stripe/create-checkout-session -i

如果返回的头里能看到Access-Control-Allow-Origin: http://localhost:3001,说明CORS配置已经生效;如果没有,检查中间件的执行顺序(你的代码里先挂载cors再挂载路由,顺序是对的),或者有没有其他中间件拦截了OPTIONS请求。

3. 前端Axios请求的小调整

虽然你的Axios请求配置看起来没问题,但可以和后端的CORS配置保持一致,明确加上跨域凭证配置(如果后端开启了credentials: true的话):

const response = await axios.post('http://localhost:5001/api/stripe/create-checkout-session', {
  name: "Basic Plan",
  price: 1000,
  successUrl: "http://localhost:3001/success",
  cancelUrl: "http://localhost:3001/cancel"
}, {
  headers: {
    'Content-Type': 'application/json'
  },
  withCredentials: true // 和后端的credentials配置保持一致
});

4. 清除浏览器缓存

有时候浏览器会缓存之前的CORS响应头,导致新的配置不生效,建议用隐身模式打开前端页面测试,或者手动清空浏览器缓存后再试。

额外检查点

  • 确认后端服务确实运行在http://localhost:5001,没有端口配置错误;
  • 检查前端请求的API URL是否完全正确(你的代码里是对的,没问题);
  • 如果后续部署到生产环境,记得把CORS的origin改成生产环境的前端域名,不要用*。

你提供的错误日志与代码片段

前端控制台错误日志

Billing-7ca61e132a5214f3.js:1 Error creating checkout session: 
V
code
: 
"ERR_NETWORK"
config
: 
{transitional: {…}, adapter: Array(3), transformRequest: Array(1),        
transformResponse: Array(1), timeout: 0, …}
message
: 
"Network Error"
name
: 
"AxiosError"
request
: 
XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0,    
withCredentials: false, upload: XMLHttpRequestUpload, …}
stack
: 
"AxiosError: Network Error\n    at m.onerror    
(http://localhost:3001/_next/static/chunks/988-fcb0a835e46419aa.js:1:39051)\n       
at ts.request (http://localhost:3001/_next/static/chunks/988-
fcb0a835e46419aa.js:1:46641)\n    at async i 
(http://localhost:3001/_next/static/chunks/pages/billing/Billing-  
7ca61e132a5214f3.js:1:1042)"
[[Prototype]]
: 
Error
i   @   Billing-7ca61e132a5214f3.js:1

后端index.js

const express = require("express");
const cors = require("cors");
require("dotenv").config();

const app = express();
const PORT = process.env.PORT || 5001;

// Middleware
app.use(cors());
app.use(express.json());

// Import routes
const stripeRoutes = require("./routes/stripe");
app.use("/api/stripe", stripeRoutes);

// Test route
app.get('/api/test', (req, res) => {
res.send('API is working!');
});

// Start server
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));

前端billing.js

import React from "react";
import { loadStripe } from "@stripe/stripe-js";
import { Elements } from "@stripe/react-stripe-js";
import { useUser } from '../../context/UserContext';
import axios from 'axios';

const stripePromise = loadStripe("your-publishable-key");

const Billing = () => {
const userContext = useUser();
const subscriptionStatus = userContext?.subscriptionStatus;
const setSubscriptionStatus = userContext?.setSubscriptionStatus;

const handleSubscriptionChange = async (priceId) => {
try {
  console.log('Creating checkout session...');
  const response = await axios.post('http://localhost:5001/api/stripe/create-checkout-session', {
    name: "Basic Plan",
    price: 1000,
    successUrl: "http://localhost:3001/success",
    cancelUrl: "http://localhost:3001/cancel"
  }, {
    headers: {
      'Content-Type': 'application/json'
    }
  });
  const { id } = response.data;
  console.log('Checkout session created:', id);
  const stripe = await stripePromise;
  const { error } = await stripe.redirectToCheckout({ sessionId: id });
  if (error) {
    console.error('Error redirecting to checkout:', error);
  }
} catch (error) {
  console.error('Error creating checkout session:', error);
  console.error('Error details:', error.response ? error.response.data :     
error.message);
}
};

return (
<Elements stripe={stripePromise}>
  <div>
    <h1>Billing</h1>
    <p>Manage your billing information here.</p>
    <p>Current subscription status: {subscriptionStatus}</p>
    <button onClick={() =>   
 handleSubscriptionChange('price_1Hh1Y2I4s2eZvKYlo2L8U7c2')}>Activate 
 Subscription</button>
    <button onClick={() => 
 handleSubscriptionChange('price_1Hh1Y2I4s2eZvKYlo2L8U7c3')}>Deactivate    
 Subscription</button>
  </div>
</Elements>
);
};

export default Billing;

后端stripe.js路由

const express = require('express');
const router = express.Router();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

router.post('/create-checkout-session', async (req, res) => {
const { name, price, successUrl, cancelUrl } = req.body;

console.log('Received request to create checkout session');
console.log('Request body:', req.body);

try {
const session = await stripe.checkout.sessions.create({
  payment_method_types: ['card'],
  line_items: [
    {
      price_data: {
        currency: 'usd',
        product_data: {
          name: name,
        },
        unit_amount: price,
      },
      quantity: 1,
    },
  ],
  mode: 'payment',
  success_url: successUrl,
  cancel_url: cancelUrl,
 });

console.log('Checkout session created:', session.id);
res.json({ id: session.id });
} catch (error) {
console.error('Error creating checkout session:', error);
res.status(500).json({ error: error.message });
}
});

module.exports = router;

备注:内容来源于stack exchange,提问作者Erik Galve

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:00:29