在使用生产服务器之前,我在本地主机中访问后端没有任何问题,然后遇到 CORS 错误。我正在使用 Next.js 后端和 Vite/React 前端。
项目结构:
backend
middleware
cors.js
pages
api
create-checkout-session.js
.env.local
src
routes
Checkout.jsx
.env.local
backend/middleware/cors.js
:
import Cors from 'cors';
const allowedOrigins = [
process.env.NEXT_PUBLIC_FRONTEND_URL.replace(/\/+$/, ''),
process.env.LOCAL_FRONTEND_URL.replace(/\/+$/, '')
];
const corsMiddleware = Cors({
methods: ['GET', 'HEAD', 'POST', 'OPTIONS'],
origin: (origin, callback) => {
if (!origin || origin === 'null') {
callback(null, true); // Allow requests with null origin (e.g., localhost file:// requests)
return;
}
const normalizedOrigin = origin.replace(/\/+$/, '');
if (allowedOrigins.includes(normalizedOrigin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
}
});
function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
}
export default corsMiddleware;
export { runMiddleware };
backend/pages/api/create-checkout-session.js
:
import { runMiddleware } from '../../middleware/cors';
import corsMiddleware from '../../middleware/cors';
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
await runMiddleware(req, res, corsMiddleware);
if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin || 'null');
res.status(200).end();
return;
}
if (req.method === 'POST') {
const { amount, originUrl } = req.body;
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{
price_data: {
currency: 'usd',
product_data: {
name: 'Total Amount',
},
unit_amount: amount,
},
quantity: 1,
}],
mode: 'payment',
success_url: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/success`,
cancel_url: originUrl,
});
res.setHeader('Access-Control-Allow-Origin', req.headers.origin || 'null');
res.status(200).json({ id: session.id });
} catch (error) {
res.status(500).json({ statusCode: 500, message: error.message });
}
} else {
res.setHeader('Allow', ['POST']);
res.status(405).end('Method Not Allowed');
}
}
.env.local
(后端):
STRIPE_SECRET_KEY=sk_test_*****************
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_***************
NEXT_PUBLIC_API_URL=https://api.lotus-dev.net
LOCAL_API_URL=http://localhost:3000
NEXT_PUBLIC_FRONTEND_URL=https://celebritymolds.com
LOCAL_FRONTEND_URL=http://localhost:5173
触发结帐的函数:
const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLIC_KEY);
const handleProceedToCheckout = async () => {
setLoading(true);
const stripe = await stripePromise;
const totalAmount = cart.reduce((sum, product) => sum + product.price * product.quantity, 0) + 30;
const body = {
amount: Math.round(totalAmount * 100), // Stripe expects amount in cents
originUrl: window.location.href,
};
const headers = {
'Content-Type': 'application/json',
};
const apiUrl = import.meta.env.MODE === 'development'
? import.meta.env.VITE_LOCAL_API_URL
: import.meta.env.VITE_API_URL;
try {
const response = await fetch(`${apiUrl}/api/create-checkout-session`, {
method: 'POST',
headers: headers,
body: JSON.stringify(body),
});
console.log('Response:', response); // Inspect the response
if (!response.ok) {
throw new Error('Network response was not ok');
}
const session = await response.json();
const result = await stripe.redirectToCheckout({
sessionId: session.id,
});
if (result.error) {
console.error('Error redirecting to checkout:', result.error.message);
}
} catch (error) {
console.error('Error creating checkout session:', error);
} finally {
setLoading(false);
}
};
.env.local
(前端):
VITE_STRIPE_PUBLIC_KEY=pk_test_***********
VITE_API_URL=https://api.lotus-dev.net
VITE_LOCAL_API_URL=http://localhost:3000
VITE_FRONTEND_URL=https://celebritymolds.com
VITE_LOCAL_FRONTEND_URL=http://localhost:5173
添加了日志记录和一些 cors 标头,更改是不言自明的。请尝试以下并让我知道!
import { runMiddleware } from '../../middleware/cors';
import corsMiddleware from '../../middleware/cors';
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
await runMiddleware(req, res, corsMiddleware);
res.setHeader('Access-Control-Allow-Origin', req.headers.origin || 'null'); // Ensure CORS header
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS'); // Ensure allowed methods
res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // Ensure allowed headers
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
if (req.method === 'POST') {
const { amount, originUrl } = req.body;
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{
price_data: {
currency: 'usd',
product_data: {
name: 'Total Amount',
},
unit_amount: amount,
},
quantity: 1,
}],
mode: 'payment',
success_url: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/success`,
cancel_url: originUrl,
});
res.status(200).json({ id: session.id });
} catch (error) {
res.status(500).json({ statusCode: 500, message: error.message });
}
} else {
res.setHeader('Allow', ['POST']);
res.status(405).end('Method Not Allowed');
}
}
中间件/cors.js
const corsMiddleware = Cors({
methods: ['GET', 'HEAD', 'POST', 'OPTIONS'],
origin: (origin, callback) => {
console.log(`Origin: ${origin}`); // Added for debugging
if (!origin || origin === 'null') {
callback(null, true); // Allow requests with null origin (e.g., localhost file:// requests)
return;
}
const normalizedOrigin = origin.replace(/\/+$/, '');
if (allowedOrigins.includes(normalizedOrigin)) {
callback(null, true);
} else {
console.log(`Blocked by CORS: ${normalizedOrigin}`); // Added for debugging
callback(new Error('Not allowed by CORS'));
}
}
});