使用Stripe Payment API出现Failed to Fetch错误的排查求助
问题:React+Express+Stripe集成时出现Failed to Fetch错误
我用React、Express和Stripe API构建了一个简单Web应用,点击跳转Stripe外部支付页面时触发了Failed to Fetch错误,除这个问题外,前端UI等其他功能都正常,不确定问题出在哪。
错误信息
Uncaught runtime errors: × ERROR Failed to fetch TypeError: Failed to fetch at checkout (http://localhost:3000/static/js/bundle.js:479:11) at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:22436:18) at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:22480:20) at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:22537:35) at invokeGuardedCallbackAndCatchFirstError (http://localhost:3000/static/js/bundle.js:22551:29) at executeDispatch (http://localhost:3000/static/js/bundle.js:26694:7) at processDispatchQueueItemsInOrder (http://localhost:3000/static/js/bundle.js:26720:11) at processDispatchQueue (http://localhost:3000/static/js/bundle.js:26731:9) at dispatchEventsForPlugins (http://localhost:3000/static/js/bundle.js:26740:7) at http://localhost:3000/static/js/bundle.js:26900:16
Navbar.js代码
import {Button, Container, Navbar, Modal} from 'react-bootstrap'; import { useState, useContext } from 'react'; import { CartContext } from "../CartContext"; import CartProduct from './CartProduct'; function NavbarComponent() { const cart = useContext(CartContext); const [show, setShow] = useState(false); // 初始不显示购物车弹窗 const handleClose = () => setShow(false); const handleShow = () => setShow(true); const checkout = async () => { await fetch('http://localhost:4000/checkout', { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({items: cart.items}) }).then((response) => { return response.json(); }).then((response) => { if(response.url) { window.location.assign(response.url); // 跳转至Stripe支付页 } }); } const productsCount = cart.items.reduce((sum, product) => sum + product.quantity, 0); return ( <> <Navbar expand="sm"> <Navbar.Brand href="/">Test</Navbar.Brand> <Navbar.Toggle /> <Navbar.Collapse className="justify-content-end"> <Button onClick={handleShow}>Cart ({productsCount} Items)</Button> </Navbar.Collapse> </Navbar> <Modal show={show} onHide={handleClose}> <Modal.Header closeButton> <Modal.Title>Shopping Cart</Modal.Title> </Modal.Header> <Modal.Body> {productsCount > 0 ? <> <p>Items in your cart:</p> {cart.items.map( (currentProduct, idx) => ( <CartProduct key={idx} id={currentProduct.id} quantity={currentProduct.quantity}></CartProduct> ))} <h1>Total: {cart.getTotalCost().toFixed(2)}</h1> <Button variant="success" onClick={checkout}> Purchase items! </Button> </> : <h1>There are no items in your cart!</h1> } </Modal.Body> </Modal> </> ) } export default NavbarComponent;
server.js代码
const express = require('express'); var cors = require('cors'); const stripe = require('stripe')(''); const app = express(); app.use(cors()); app.use(express.static("public")); app.use(express.json()); app.post("/checkout", async (req, res) => { console.log(req.body); const items = req.body.items; let lineItems = []; items.forEach((item)=> { lineItems.push( { price: item.id, quantity: item.quantity } ); }); const session = await stripe.checkout.sessions.create({ line_items: lineItems, mode: 'payment', success_url: "http://localhost:3000/success", cancel_url: "http://localhost:3000/cancel" }); res.send(JSON.stringify({ url: session.url })); }); app.listen(4000, () => console.log("Listening on port 4000"));
疑问
请问该问题是否与本地主机/连接配置有关?
排查与解决方案
修复Stripe密钥配置:你的server.js中
stripe('')是空的,必须填入有效的Stripe测试/生产密钥(如sk_test_xxxxxx),空密钥会直接导致Stripe API调用失败,后端无法生成支付会话,前端自然会收到网络错误。这是最核心的问题。完善CORS配置:虽然你使用了
cors()中间件,但可以指定明确的允许源来避免潜在的跨域问题:app.use(cors({ origin: 'http://localhost:3000' }));添加后端错误捕获:当前后端没有错误处理逻辑,Stripe调用失败时会直接抛出错误导致请求中断,给
/checkout接口添加try-catch:app.post("/checkout", async (req, res) => { try { console.log(req.body); const items = req.body.items; let lineItems = []; items.forEach((item)=> { lineItems.push({ price: item.id, quantity: item.quantity }); }); const session = await stripe.checkout.sessions.create({ line_items: lineItems, mode: 'payment', success_url: "http://localhost:3000/success", cancel_url: "http://localhost:3000/cancel" }); res.json({ url: session.url }); } catch (error) { console.error("Stripe会话创建失败:", error); res.status(500).json({ error: error.message }); } });这样能在控制台看到具体错误信息,方便定位问题。
增强前端错误处理:当前前端fetch没有处理错误状态,添加try-catch捕获网络或HTTP错误:
const checkout = async () => { try { const response = await fetch('http://localhost:4000/checkout', { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({items: cart.items}) }); if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`); } const data = await response.json(); if(data.url) { window.location.assign(data.url); } } catch (error) { console.error('结账失败:', error); alert('支付请求失败,请稍后重试'); } }验证本地连接:确认后端服务确实在4000端口运行,可通过Postman或curl测试
POST http://localhost:4000/checkout接口,检查是否返回有效的Stripe会话URL。
内容的提问来源于stack exchange,提问作者Mason Bose
相关产品推荐
相关产品推荐

