Next.js集成Stripe支付时API请求返回404错误排查求助
Next.js集成Stripe支付API 404错误排查方案
问题描述
用Next.js搭建电商网站并集成Stripe支付功能时,调用API返回404错误。已将Stripe密钥存储在环境变量中(知晓并非最佳实践,暂未找到替代方案),检查过路由路径、变量拼写,前后端端口与主机也匹配(控制台可显示相关信息),仍无法定位问题根源,寻求排查思路。
相关代码文件
Shop.js
import Link from "next/link"; import { useState } from "react"; import Image from "next/image"; import bag from "pages/public/next.svg"; import { CreateCheckOutSession } from "../../components/Api/create-checkout-session"; function Shop() { // const [item, setItem] = useState({ // name: "Apple AirPods", // description: "Latest Apple AirPods.", // image: bag, // quantity: 0, // price: 999, // }); const [item, setItem] = useState({ name: "Apple AirPods", description: "Latest Apple AirPods.", image: "/path/to/bag.png", quantity: 0, image: bag, price: 999, // string instead of component // ... }); const simpleItem = { name: item.name, description: item.description, price: item.price, }; const changeQuantity = (value, number) => { setItem({ ...item, quantity: Math.max(0, value) }); }; const onQuantityPlus = () => { changeQuantity(item.quantity + 1); }; const onQuantityMinus = () => { changeQuantity(item.quantity - 1); }; const onInputChange = (e) => { changeQuantity(parseInt(e.target.value)); }; return ( <div className="body-shop"> <nav> <div className="arrow"> <Link href="/"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-left-square" viewBox="0 0 16 16" > <path fillRule="evenodd" d="M15 2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2zM0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm11.5 5.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H11.5z" /> </svg> </Link> </div> <div className="group"> <Link href="/">Home</Link> <Link href="./About">About</Link> <Link href="./blog">Blog</Link> <Link href="./shop">Shop</Link> <Link href="./services">Personal styled Services</Link> </div> </nav> <h1>Shop</h1> <main> <div className="shadow-lg border rounded p-2 "> <Image src={item.image} width={300} height={150} /> <h2 className="text-2xl">$ {item.price}</h2> <h3 className="text-xl">{item.name}</h3> <p className="text-gray-500">{item.description}</p> <p className="text-sm text-gray-600 mt-1">Quantity:</p> <div className="border rounded"> <button onClick={onQuantityMinus} className="bg-blue-500 py-2 px-4 text-white rounded hover:bg-blue-600" > - </button> <input type="number" className="p-2" onChange={onInputChange} value={item.quantity} /> <button onClick={onQuantityPlus} className="bg-blue-500 py-2 px-4 text-white rounded hover:bg-blue-600" > + </button> </div> <p>Total: ${item.quantity * item.price}</p> <button disabled={item.quantity === 0} onClick={() => CreateCheckOutSession(item)} className="bg-blue-500 hover:bg-blue-600 text-white block w-full py-2 rounded mt-2 disabled:cursor-not-allowed disabled:bg-blue-100" > Buy </button> </div> </main> </div> ); } export default Shop;
create-checkout-session.js
import { loadStripe } from "@stripe/stripe-js"; import axios from "axios"; const publishableKey = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY; const stripePromise = loadStripe(publishableKey); export const CreateCheckOutSession = async (item) => { const stripe = await stripePromise; // 修正API请求路径,指向正确的Next.js API路由 const checkoutSession = await axios.post("/api/create-stripe-session", { item: item, }); const result = await stripe.redirectToCheckout({ sessionId: checkoutSession.data.id, }); if (result.error) { alert(result.error.message); } };
create-stripe-session.js
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); async function CreateStripeSession(req, res) { const { item } = req.body; const redirectURL = process.env.NODE_ENV === "development" ? "http://localhost:3000" : "https://stripe-checkout-next-js-demo.vercel.app"; const transformedItem = { price_data: { currency: "usd", product_data: { // 注意:Stripe要求图片URL必须是公网可访问的,本地路径无法被识别 images: [item.image], name: item.name, }, unit_amount: item.price * 100, }, description: item.description, quantity: item.quantity, }; const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], line_items: [transformedItem], mode: "payment", success_url: redirectURL + "?status=success", cancel_url: redirectURL + "?status=cancel", metadata: { images: item.image, }, }); res.json({ id: session.id }); } export default CreateStripeSession;
核心排查点与修复建议
- API路由位置错误:Next.js要求API路由文件必须放在
pages/api目录下(App Router对应app/api)。你的create-stripe-session.js当前在components/Api目录,无法被识别为API端点,直接导致404。修复:将该文件移动到pages/api目录,请求路径对应/api/create-stripe-session。 - 请求URL传错:原代码中直接将
CreateStripeSession函数作为axios请求的URL,这是完全错误的。必须传入字符串格式的API路径,如/api/create-stripe-session。 - 请求参数不匹配:后端期望从
req.body.item获取商品数据,但前端原代码传的是组件本身{ Shop: Shop },完全不符合要求。修复:在Shop组件的Buy按钮点击时,将item状态作为参数传入CreateCheckOutSession,并在请求时正确传递{ item: item }。 - 环境变量验证:确认
STRIPE_SECRET_KEY和NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY在.env.local文件中拼写正确,且Next.js服务已重启加载最新变量;生产环境需确保平台(如Vercel)已配置对应环境变量。 - 图片URL问题:Stripe要求商品图片必须是公网可访问的URL,本地路径(如
/path/to/bag.png)或Next.js的Image组件资源无法被Stripe识别,后续测试需替换为公开图片链接。
内容的提问来源于stack exchange,提问作者Andrea Lopez Bravo
相关产品推荐
相关产品推荐

