
本文详解如何在 next.js 13(app router)中安全、合规地集成 stripe,通过服务端创建 checkout session 并重定向用户至 stripe 托管的结账页面,避免前端暴露密钥。
本文详解如何在 next.js 13(app router)中安全、合规地集成 stripe,通过服务端创建 checkout session 并重定向用户至 stripe 托管的结账页面,避免前端暴露密钥。
在 Next.js 13 的 App Router 架构下,集成 Stripe 必须严格遵循服务端优先(Server-Side Only)原则:敏感操作(如调用 stripe.checkout.sessions.create)必须在 Server Component 或 Route Handler(API 路由)中完成,绝不可在客户端组件或浏览器环境中使用 Secret Key。以下是完整、可落地的集成步骤:
✅ 步骤 1:安装与环境配置
首先安装 Stripe Node SDK,并设置环境变量:
npm install stripe
在 .env.local 中安全存储密钥(仅服务端可读):
STRIPE_SECRET_KEY=sk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
⚠️ 注意:STRIPE_SECRET_KEY 不能被客户端访问(Next.js 自动屏蔽以 NEXT_PUBLIC_ 开头以外的环境变量),而 NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY 可用于前端初始化 Stripe.js(如后续需自定义支付元素)。
✅ 步骤 2:创建服务端会话(Route Handler)
在 app/api/create-checkout-session/route.ts 中编写 API 路由(推荐使用 TypeScript):
import { NextResponse } from 'next/server';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2024-06-20',
});
export async function POST() {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'usd',
product_data: { name: 'Premium Subscription' },
unit_amount: 999, // $9.99 in cents
},
quantity: 1,
},
],
mode: 'payment',
success_url: `${process.env.NEXT_PUBLIC_APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/pricing`,
});
return NextResponse.json({ url: session.url }, { status: 200 });
} catch (err) {
console.error('Stripe session creation error:', err);
return NextResponse.json(
{ error: 'Failed to create checkout session' },
{ status: 500 }
);
}
}? 关键点:session.url 是 Stripe 托管的唯一结账页面地址(如 https://checkout.stripe.com/c/pay/...),调用后立即重定向即可,无需前端渲染表单。
✅ 步骤 3:前端触发跳转(Client Component)
在 app/pricing/page.tsx 等客户端页面中,使用 useRouter 触发跳转:
'use client';
import { useRouter } from 'next/navigation';
export default function PricingPage() {
const router = useRouter();
const handleCheckout = async () => {
try {
const res = await fetch('/api/create-checkout-session', {
method: 'POST',
});
const { url } = await res.json();
if (url) router.push(url); // 重定向至 Stripe 结账页
} catch (error) {
console.error('Checkout failed:', error);
alert('Unable to start checkout. Please try again.');
}
};
return (
<div>
<h2>Premium Plan</h2>
<p>$9.99/month</p>
<button onClick={handleCheckout} className="btn">
Subscribe Now
</button>
</div>
);
}✅ 后续建议与注意事项
- Webhook 验证:务必在生产环境配置 Stripe Webhook(如 /api/webhook),监听 checkout.session.completed 事件以确认支付成功并更新数据库;
- 价格管理:避免硬编码 price_xxx ID,建议通过 Stripe Dashboard 创建 Price 对象,或使用 Stripe Products API 动态获取;
- 测试模式:开发时使用 test 模式密钥 + Stripe Test Cards,例如 4242 4242 4242 4242;
- SSR/ISR 兼容性:该方案完全兼容 Next.js 13 的服务端渲染(SSR)和静态生成(ISR),无 hydration 冲突风险。
通过以上结构化实现,你将获得一个安全、可扩展且符合 Stripe 最佳实践的 Next.js 13 支付集成方案——无需手写表单、不暴露密钥、无缝支持 App Router 架构。


















