在Next.js中使用Stripe时始终返回undefined的问题排查
Next.js中Stripe产品列表返回undefined的问题解决
问题场景
你的配置和代码如下:
.env.local文件:
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY = pk_test_apikeycontinues STRIPE_SECRET_KEY = sk_test_apikeycontinues
./app/utils/stripe.js:
import Stripe from 'stripe'; export const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
- 首页代码(两种写法均返回undefined):
第一种:
'use client' import { stripe } from "./utils/stripe"; export default function Home({ products }) { console.log(products); return ( <div> home </div> ) } export async function getStaticProps() { const inventory = await stripe.products.list({ limit: 5, }); return { props: { products: inventory, }, }; }
第二种(直接写入密钥):
'use client' import Stripe from 'stripe'; export const stripe = Stripe("sk_test_apikeycontinues"); export default function Home({ products }) { console.log(products); return ( <div> home </div> ) } export async function getStaticProps() { const inventory = await stripe.products.list({ limit: 5, }); return { props: { products: inventory, }, }; }
Stripe测试环境已有库存,但控制台始终打印undefined。
核心错误原因
'use client'导致getStaticProps失效:在Next.js 13+的App Router中,添加'use client'指令会将整个组件标记为客户端组件,而getStaticProps仅能在服务器组件中运行,客户端组件中的getStaticProps不会被执行,因此products参数始终为undefined。- 密钥暴露风险:直接在客户端代码中使用Stripe的
STRIPE_SECRET_KEY会导致敏感密钥泄露,这是严重的安全问题,绝对禁止这么做。
解决步骤
1. 移除页面的'use client'指令
让首页组件成为服务器组件(App Router中默认就是服务器组件,无需额外声明),这样getStaticProps才能正常执行。
2. 确保Stripe实例仅在服务器端使用
保持./app/utils/stripe.js为服务器组件(不要加'use client'),并指定Stripe API版本避免兼容性问题:
import Stripe from 'stripe'; export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-06-20', // 替换为你使用的Stripe API版本 });
3. 修正getStaticProps的返回值
Stripe的products.list()返回的是包含data数组的对象,通常需要传递data而非整个对象给组件:
import { stripe } from "./utils/stripe"; export default function Home({ products }) { console.log(products); return ( <div> home </div> ) } export async function getStaticProps() { const inventory = await stripe.products.list({ limit: 5, }); return { props: { products: inventory.data, // 传递data数组 }, }; }
4. 若需客户端交互,拆分组件
如果页面需要客户端交互(比如点击事件、状态管理),将客户端逻辑拆分到单独的'use client'组件中,页面主体保持为服务器组件:
- 创建客户端组件
./app/components/ProductList.js:
'use client'; export default function ProductList({ products }) { // 这里可以编写客户端交互逻辑 return ( <div> {products.map(product => ( <div key={product.id}>{product.name}</div> ))} </div> ); }
- 修改首页服务器组件:
import { stripe } from "./utils/stripe"; import ProductList from "./components/ProductList"; export default function Home({ products }) { console.log(products); return ( <div> <ProductList products={products} /> </div> ) } export async function getStaticProps() { const inventory = await stripe.products.list({ limit: 5, }); return { props: { products: inventory.data, }, }; }
内容的提问来源于stack exchange,提问作者Israel Panopio
相关产品推荐
相关产品推荐

