Vue Router点击后刷新页面而非跳转:两段代码差异排查
问题描述
点击结算按钮时,可成功获取后端返回的有效Stripe跳转URL,但页面仅刷新,无法跳转到目标地址。此前有可用代码版本,复制到当前项目后失效,重构后问题依旧。以下是正常运行代码与异常代码,请求分析差异、问题原因及修复方案。
可正常运行代码
前端代码
<script setup> import { ref, onBeforeMount } from "vue"; import CheckoutSummary from "../components/CheckoutSummary.vue"; import CheckoutButton from "../components/CheckoutButton.vue"; // 响应式数据 const isLoading = ref(false); const cart = ref([]); // 获取购物车数据 onBeforeMount(async () => { const response = await fetch("/api/shopping-cart").then((r) => r.json()); cart.value = response.cart; }); // 按钮点击事件处理 const redirectToStripe = async () => { isLoading.value = true; const response = await fetch("/api/create-checkout-session", { method: "POST", }); const { url } = await response.json(); window.location.href = url; }; </script>
后端代码
// 创建结算会话 app.post("/create-checkout-session", async (req, res) => { // 提取Stripe价格ID和数量,生成数组 const lineItems = USER_SHOPPING_CART.map((item) => { return { price: item.stripePriceId, quantity: item.quantity, }; }); const session = await stripe.checkout.sessions.create({ mode: "payment", line_items: lineItems, success_url: `http://localhost:3000/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `http://localhost:3000/`, }); return res.send({ url: session.url }); });
异常代码
前端代码
<script setup> import { computed } from "vue"; import { useRouter } from "vue-router"; import { useStore } from "vuex"; const router = useRouter(); // eslint-disable-next-line no-unused-vars, no-undef const props = defineProps({ isLoading: Boolean, }); const store = useStore(); const cartItems = computed(() => store.getters.getCheckout); const redirectToStripe = async () => { const { url } = await fetch("http://localhost:5000/create-checkout-session", { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify(cartItems.value), }).then((response) => response.json()); console.log("url=", url); router.go(url); }; </script>
后端代码
app.post("/create-checkout-session", async (req, res) => { // 提取Stripe价格ID和数量,生成数组 const lineItems = req.body.map((item) => { console.log("lineItems= ", item.item.priceId, item.item.quantity); return { price: item.item.priceId, quantity: item.item.quantity, }; }); const session = await stripe.checkout.sessions.create({ mode: "payment", line_items: lineItems, success_url: `http://localhost:8080/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `http://localhost:8080/`, }); return res.send({ url: session.url }); });
差异分析与问题原因
1. 前端跳转逻辑错误(核心问题)
正常代码使用window.location.href = url;直接触发浏览器原生跳转,适用于外部域名(如Stripe结算页);异常代码使用router.go(url),但**router.go()的参数是跳转步数(如+1前进、-1后退),并非URL**。传入URL会被解析为NaN,等同于调用router.go(0),即刷新当前页面,这就是跳转失效的直接原因。
2. 购物车数据传递与解析差异
- 正常代码后端直接使用全局变量
USER_SHOPPING_CART生成结算项;异常代码通过POST请求体传递Vuex中的购物车数据,后端从req.body读取。 - 异常代码后端解析
req.body时使用item.item.priceId,需确认Vuex返回的购物车数据是否为嵌套item对象的结构。若结构不匹配,会生成无效的结算项,虽当前能拿到URL,但Stripe页面可能显示购物车为空。
3. 请求路径与跨域配置
异常代码前端使用硬编码的完整域名http://localhost:5000,正常代码用相对路径。虽当前能获取URL说明跨域配置无问题,但硬编码域名不利于后续部署。
修复方案
1. 修正前端跳转逻辑
将router.go(url)替换为原生跳转方式,二选一即可:
// 方案1:最可靠的外部跳转方式 window.location.href = url; // 方案2:Vue Router支持外部URL跳转(需确保url是完整http/https地址) router.push(url);
2. 验证并修正购物车数据结构
检查Vuex中getCheckout返回的数据结构:
- 若数据结构为
[{ priceId: 'xxx', quantity: 1 }],需修改后端代码:
const lineItems = req.body.map((item) => { return { price: item.priceId, quantity: item.quantity, }; });
- 若数据确实是嵌套
item对象的结构,则无需修改后端,但需确保数据传递无遗漏。
3. 可选:统一请求路径(避免硬编码)
在Vue项目配置文件中设置代理(以Vite为例):
// vite.config.js export default { server: { proxy: { '/api': { target: 'http://localhost:5000', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } }
然后将前端请求改为相对路径:
fetch("/api/create-checkout-session", { /* ... */ })
内容的提问来源于stack exchange,提问作者Eric Andre
相关产品推荐
相关产品推荐

