NextJS部署后Stripe结账报500及ERR_HTTP_HEADERS_SENT错误
解决Stripe结账部署后500错误及重复响应头问题
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
这个错误的直接原因是同一个请求处理流程中发送了两次响应,导致HTTP头被重复设置。结合你的代码和Stripe已生成未支付订单的情况,具体问题及修复方案如下:
1. 修复API路由的重复响应问题
在pages/api/stripe.js中,你先调用res.status(200).json(session)返回JSON数据,紧接着又执行res.redirect(303, session.url)进行重定向。这两个操作都会向客户端发送响应头,触发重复设置的错误。
根据你的前端逻辑(前端拿到sessionId后自行调用stripe.redirectToCheckout),只需要返回session数据即可,不需要在API层做重定向。修改后的代码:
import Stripe from 'stripe'; // 注意:私钥不能用NEXT_PUBLIC前缀,避免暴露到前端 const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export default async function handler(req, res) { if (req.method === 'POST') { try { const params = { submit_type :'pay', mode:'payment', payment_method_types:['card'], shipping_address_collection: { allowed_countries: ['IN'], }, shipping_options: [ {shipping_rate: '替换为你的Stripe运费费率ID'} ], line_items: req.body.map((item)=>{ const img = item.image[0].asset._ref; const newImage = img.replace('image-','https://cdn.sanity.io/..../').replace('-webp','.webp'); return { price_data:{ currency:'inr', product_data:{ name:item.name, images:[newImage], }, unit_amount:item.price*100, }, adjustable_quantity:{ enabled:true, minimum:1 }, quantity:item.quantity } }), success_url: `${req.headers.origin}/success`, cancel_url: `${req.headers.origin}`, } const session = await stripe.checkout.sessions.create(params); // 仅返回session数据,由前端处理重定向 res.status(200).json(session); } catch (err) { res.status(err.statusCode || 500).json(err.message); } } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); } }
2. 修正环境变量名称错误
Stripe的密钥(Secret Key)不能使用NEXT_PUBLIC_前缀,这个前缀会让变量暴露到前端代码中,存在安全风险,同时可能导致部署后密钥无法正确读取。将环境变量名从NEXT_PUBLIC_STRIPE_SECRET_KEY改为STRIPE_SECRET_KEY,并确保部署环境中已正确配置该变量。
3. 修复前端错误状态判断
在cart.js中,你使用response.statusCode判断响应状态,但Fetch API的响应对象属性是status,不是statusCode,这会导致500错误无法被正确捕获。修改代码:
const handleCheckout = async () => { const stripe = await getStripe(); const response = await fetch('/api/stripe', { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(cartItems) }); // 修正为response.status if (response.status === 500) { toast.error('结账请求失败,请重试'); return; } const data = await response.json(); toast.loading("Redirecting..."); stripe.redirectToCheckout({ sessionId: data.id }); };
额外检查点
- 确认部署环境中已正确配置
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY(公钥)和STRIPE_SECRET_KEY(私钥) - 确保
shipping_options中的shipping_rate是有效的Stripe运费费率ID,不要留占位符 - 检查Sanity图片链接替换逻辑是否正确,避免因图片URL无效导致Stripe会话创建失败
内容的提问来源于stack exchange,提问作者Subash Saravanan
相关产品推荐
相关产品推荐

