NextJS亚马逊克隆项目出现Stripe权限错误(500状态码)
问题:NextJS亚马逊克隆项目出现500错误,Stripe提示需使用密钥API密钥
问题详情
跟随教程实现亚马逊克隆项目,代码与教程完全一致,但始终触发Unhandled Runtime Error Error: Request failed with status code 500。已尝试重新生成Firebase和Stripe密钥、修改Stripe运费率,问题仍存在。项目代码托管在GitHub仓库。
终端输出关键错误信息:
StripePermissionError: 此API调用无法使用可发布API密钥,请使用密钥API密钥。你可以在Stripe账户API密钥页面找到你的所有API密钥。 ... code: 'secret_key_required', statusCode: 403
相关代码
后端API路由(/api/create-checkout-session)
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); export default async (req, res) => { const { items, email } = req.body; const transformedItems = items.map((item) => ({ price_data: { currency: "gbp", unit_amount: item.price * 100, product_data: { name: item.title, images: [item.image], description: item.description, }, }, quantity: 1, })); const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], shipping_options: [ { shipping_rates: ["shr_1M97piHPvZNNoU6bvw5ut7Oy"], }, ], shipping_address_collection: { allowed_countries: ["GB", "US", "CA"], }, line_items: transformedItems, mode: "payment", success_url: `${process.env.HOST}/success`, cancel_url: `${process.env.HOST}/checkout`, metadata: { email, images: JSON.stringify(items.map((item) => item.image)), }, }); res.status(200).json({ id: session.id }); };
Checkout组件
import Image from "next/image"; import React from "react"; import { useSelector } from "react-redux"; import CheckoutProduct from "../components/CheckoutProduct"; import Header from "../components/Header"; import { selectItems, selectTotal } from "../slices/basketSlice"; import Currency from "react-currency-formatter"; import { useSession } from "next-auth/client"; import { loadStripe } from "@stripe/stripe-js"; import axios from "axios"; const stripePromise = loadStripe(process.env.stripe_public_key); function Checkout() { const items = useSelector(selectItems); const total = useSelector(selectTotal); const [session] = useSession(); const createCheckoutSession = async () => { const stripe = await stripePromise; // 调用后端创建结账会话 const checkoutSession = await axios.post("/api/create-checkout-session", { items: items, email: session.user.email, }); // 重定向到Stripe结账页面 const result = await stripe.redirectToCheckout({ sessionId: checkoutSession.data.id, }); if (result.error) { alert(result.error.message); } }; return ( <div className="bg-gray-100"> <Header /> <main className="lg:flex max-w-screen-2xl mx-auto"> {/* 左侧购物车列表 */} <div className="flex-grow m-5 shadow-sm"> <Image src="https://links.papareact.com/ikj" width={1020} height={250} objectFit="contain" /> <div className="flex flex-col p-5 space-y-10 bg-white"> <h1 className="text-3xl border-b pb-4"> {items.length === 0 ? "你的亚马逊购物车是空的。" : "购物篮"} </h1> {items.map((item, i) => ( <CheckoutProduct key={i} id={item.id} title={item.title} rating={item.rating} price={item.price} description={item.description} category={item.category} image={item.image} hasPrime={item.hasPrime} /> ))} </div> </div> {/* 右侧结账区域 */} <div className="flex flex-col bg-white p-10 shadow-md"> {items.length > 0 && ( <> <h2 className="whitespace-nowrap"> 小计 ({items.length} 件商品):{" "} <span className="font-bold"> <Currency quantity={total} currency="GBP" /> </span> </h2> <button role="link" onClick={createCheckoutSession} disabled={!session} className={`button mt-2 ${! session && "from-gray-300 to-gray-500 border-gray-200 text-gray-300 cursor-not-allowed" }`} > {!session ? "登录以结账" : "继续结账"} </button> </> )} </div> </main> </div> ); } export default Checkout;
解决方案
核对Stripe密钥类型:
- Stripe密钥分两种:密钥(Secret Key)以
sk_开头,仅用于后端;可发布密钥(Publishable Key)以pk_开头,仅用于前端。 - 确保环境变量
STRIPE_SECRET_KEY的值是sk_开头的密钥,而非pk_开头的可发布密钥。
- Stripe密钥分两种:密钥(Secret Key)以
检查环境变量配置:
- 打开项目根目录的
.env.local文件,确认STRIPE_SECRET_KEY的取值正确。 - 前端使用的可发布密钥,在NextJS中需要添加
NEXT_PUBLIC_前缀,比如改为NEXT_PUBLIC_STRIPE_PUBLIC_KEY,并在Checkout组件中对应修改为process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY,否则前端无法读取该变量。
- 打开项目根目录的
重启开发服务器:
修改环境变量后,必须重启NextJS开发服务器,确保新的环境变量生效。验证Stripe运费率ID:
确认shipping_rates中的ID是你Stripe账户中已创建的有效运费率ID,避免因无效ID导致额外错误。
内容的提问来源于stack exchange,提问作者user15339125
相关产品推荐
相关产品推荐

