Node.js + Express集成Stripe结账时无法正常跳转至结账页面的问题
Node.js + Express集成Stripe结账时无法正常跳转至结账页面的问题
Hey,我帮你梳理下代码里的问题,应该能解决你现在的跳转异常以及潜在的Stripe配置错误:
首先说核心问题:为什么点击按钮后显示JSON而不是跳转?
你提到的现象,大概率是两种情况之一:
- 你可能直接在浏览器地址栏访问了
GET /cart/checkout路由——因为你同时定义了GET和POST两个checkout接口,GET请求会直接返回JSON,浏览器就会显示这个字符串; - 前端fetch请求因为后端的Stripe配置错误触发了异常,没走到跳转逻辑。
下面一步步解决:
1. 前端代码的致命错误:无法直接访问后端的req.session
在你的checkout.ejs里,fetch请求的body写了:
body: JSON.stringify({ items: req.session.cart, }),
前端浏览器完全拿不到后端的req.session对象,这里的req.session.cart在前端会变成undefined!虽然你的后端没用到这个参数,但这是无效代码,还可能干扰后续逻辑。建议改成从EJS渲染购物车数据到前端:
<script> // 先把后端购物车数据渲染到前端全局变量 const cartItems = <%- JSON.stringify(req.session.cart) %>; </script>
然后在fetch里用cartItems代替req.session.cart。
2. Stripe Session配置的关键错误:金额和数量搞混了
后端创建Stripe会话的代码里,有两个严重错误:
line_items: req.session.cart.map(item => { return { price_data: { // ... unit_amount: item.itemPrice // 错误:Stripe要求传入最小货币单位(英镑是便士) }, quantity: item.quantity * 100 // 错误:数量不需要乘100! } }),
unit_amount:如果你的item.itemPrice是英镑数值(比如10代表10英镑),必须乘以100转换成便士,也就是unit_amount: item.itemPrice * 100;quantity:直接写item.quantity就行,乘100会导致购买数量变成实际的100倍,Stripe肯定会报错。
这个错误会直接导致Stripe会话创建失败,后端返回500错误,前端自然无法拿到跳转URL。
修复后的完整代码参考
后端控制器(customer_cart.js)
const AllProduct = require('../database_models/allproduct'); const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY) module.exports.checkout = async (req, res) => { if (!req.session.cart) { req.flash('error', 'There are no items to be checked out'); return res.redirect('/'); // 加return避免后续代码执行 } try { const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], mode: 'payment', line_items: req.session.cart.map(item => { return { price_data: { currency: 'gbp', product_data: { name: item.productName }, unit_amount: item.itemPrice * 100 // 转换为便士 }, quantity: item.quantity // 正确的购买数量 } }), success_url: `${process.env.SERVER_URL}/success`, cancel_url: `${process.env.SERVER_URL}/cancel` // 确保/cancel路由已定义,去掉.html后缀 }) res.json({ url: session.url }) } catch (error) { res.status(500).json({ error: error.message }) } };
前端页面(checkout.ejs)
<% layout('layouts/productboilerplate')%> <h1>TEST</h1> <button>Checkout</button> <script> // 从EJS渲染后端购物车数据到前端 const cartItems = <%- JSON.stringify(req.session.cart) %>; const button = document.querySelector("button") button.addEventListener("click", () => { fetch('/cart/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ items: cartItems }), }).then(res => { if (res.ok) return res.json() return res.json().then(json => Promise.reject(json)) }).then(({ url }) => { console.log(url) window.location.href = url // 这里会正常跳转至Stripe结账页 }).catch(error => { console.error(error) alert('结账请求失败:' + (error.error || '未知错误')) // 给用户提示错误 }) }) </script>
额外排查建议
- 测试时打开浏览器开发者工具(F12),看Network标签页的fetch请求响应是否正常,Console标签页有没有报错;
- 确保
process.env.SERVER_URL是正确的(比如http://localhost:3000),并且/success和/cancel路由已经在后端定义好; - 不要再直接访问
GET /cart/checkout,只能通过按钮触发POST请求。
备注:内容来源于stack exchange,提问作者NewtoJavaHelp
相关产品推荐
相关产品推荐

