如何使用 Next.js 克服此 CORS 错误?

问题描述 投票:0回答:1

在使用生产服务器之前,我在本地主机中访问后端没有任何问题,然后遇到 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
javascript node.js next.js cors stripe-payments
1个回答
0
投票

添加了日志记录和一些 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'));
    }
  }
});
© www.soinside.com 2019 - 2024. All rights reserved.