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

Next.js 13集成Stripe支付遇405(Method Not Allowed)错误求助

Next.js集成Stripe支付网关时405 (Method Not Allowed)错误的解决

问题场景

在Next.js应用中集成Stripe支付网关,遵循官方文档操作后遇到以下错误:

405 (Method Not Allowed)

相关代码如下:

CheckoutForm.js

// components/CheckoutForm.js
import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
import axios from 'axios';

const CheckoutForm = ({ cartItems, email }) => {
  const stripe = useStripe();
  const elements = useElements();

  const handleSubmit = async (event) => {
    event.preventDefault();
  
    if (!stripe || !elements) {
      return;
    }
  
    try {
      const response = await fetch("/api/checkout_sessions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          items: cartItems
        }),
      });
  
      const data = await response.json();
  
      // Destructure clientSecret directly from the response
      const { clientSecret } = data;
  
      // Confirm the card payment
      const result = await stripe.confirmCardPayment(clientSecret, {
        payment_method: {
          card: elements.getElement(CardElement),
          billing_details: {
            email: email,
          },
        },
      });
  
      if (result.error) {
        // Show error to your customer
        console.error(result.error.message);
      } else if (result.paymentIntent.status === "succeeded") {
        // Payment succeeded, you can redirect or show a success message
        console.log("Payment succeeded!");
        // Redirect or show success message
      }
    } catch (error) {
      console.error("Error:", error.message);
    }
  };
  

  return (
    <div className="bg-gray-200 pt-3 pb-2" >
        <small className="flex w-full justify-left">Credit / Debit Card Details</small>
    <form onSubmit={handleSubmit}>
    
    <div style={{ margin: '20px 0' }}>
      <CardElement />
    </div>
    <button className="mt-8 flex w-full justify-center rounded-md border border-transparent bg-[#f1592a] py-2 px-4 text-sm font-medium text-white shadow-sm" type="submit" disabled={!stripe}>
      Pay
    </button>
  </form>
  </div>
  );
};

export default CheckoutForm;

app/api/check_sessions/route.js

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

export default async function handler(req, res) {
  switch (req.method) {
    case "POST":
      try {

        const { items } = req.body;

        // Create an array to store line items
        const lineItems = items.map((item) => ({
            price: item.priceId, // Replace with the actual Price ID from your data
            quantity: item.quantity,
        }));


        // Create Checkout Sessions from body params.
        const session = await stripe.checkout.sessions.create({
          ui_mode: 'embedded',
          line_items: lineItems,
          mode: 'payment',
          return_url: `${req.headers.origin}/return?session_id={CHECKOUT_SESSION_ID}`,
        });

        res.send({clientSecret: session.client_secret});
      } catch (err) {
        res.status(err.statusCode || 500).json(err.message);
      }
    case "GET":
      try {
        const session = await stripe.checkout.sessions.retrieve(req.query.session_id);

        res.send({
          status: session.status,
          customer_email: session.customer_details.email
        });
      } catch (err) {
        res.status(err.statusCode || 500).json(err.message);
      }
    default:
      res.setHeader('Allow', req.method);
      res.status(405).end('Method Not Allowed');
  }
}

错误原因及修复步骤

1. API路由路径拼写不匹配

前端请求的路径是/api/checkout_sessions,但后端API文件放在app/api/check_sessions/route.js,对应路径为/api/check_sessions(少了字母o),前后路径不一致导致请求找不到正确的处理路由。

修复:

  • 要么将前端请求路径改为/api/check_sessions,要么把后端文件夹重命名为checkout_sessions,确保前后路径完全一致。

2. Next.js App Router API路由写法错误

你使用的是Next.js App Router(app/目录结构),但API路由采用了Pages Router的export default handler+switch判断写法,这不符合App Router的规范。App Router要求每个HTTP方法单独导出对应的处理函数。

修复:
将app/api/check_sessions/route.js改为以下符合App Router规范的写法:

import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export async function POST(request) {
  try {
    const { items } = await request.json();

    const lineItems = items.map((item) => ({
      price: item.priceId,
      quantity: item.quantity,
    }));

    const session = await stripe.checkout.sessions.create({
      ui_mode: 'embedded',
      line_items: lineItems,
      mode: 'payment',
      return_url: `${new URL(request.url).origin}/return?session_id={CHECKOUT_SESSION_ID}`,
    });

    return new Response(JSON.stringify({ clientSecret: session.client_secret }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (err) {
    return new Response(JSON.stringify(err.message), {
      status: err.statusCode || 500,
      headers: { 'Content-Type': 'application/json' },
    });
  }
}

export async function GET(request) {
  try {
    const { searchParams } = new URL(request.url);
    const sessionId = searchParams.get('session_id');

    const session = await stripe.checkout.sessions.retrieve(sessionId);

    return new Response(JSON.stringify({
      status: session.status,
      customer_email: session.customer_details?.email
    }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (err) {
    return new Response(JSON.stringify(err.message), {
      status: err.statusCode || 500,
      headers: { 'Content-Type': 'application/json' },
    });
  }
}

3. 原switch语句缺少break(次要问题)

即使使用Pages Router的写法,原代码中case "POST"和case "GET"分支都没有添加break,会导致POST请求执行完后继续进入GET分支,最终落入default返回405。改用App Router的写法后该问题自动解决。

额外验证点

  • 确保.env.local文件中正确配置了STRIPE_SECRET_KEY,且重启开发服务器让环境变量生效。
  • 确认cartItems中的priceId是Stripe后台创建的有效价格ID。

内容的提问来源于stack exchange,提问作者fagbemi ayodele

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 07:40:54