ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Vue3电商实战:打通登录到支付的全链路

2026/9/3 18:23:35 拓冰建站 浏览量
Vue3电商实战:打通登录到支付的全链路 Vue3 电商应用实战里“登录到支付”是那条最容易出现理解偏差的主链路。很多人做项目时页面能渲染、接口能返回、路由能跳但一旦要把用户从登录态一直带到支付结果这里就会暴露出一堆问题Token 没带上、路由守卫死循环、订单状态不同步、支付环境根本不是正式商户。判断一个 Vue3 电商实战项目值不值得拿来学习或放进简历我最先看的就是登录后的用户状态能不能稳定传递到下单支付回调之后订单能不能正确变成已支付。这个项目解决的就是这一整条链路。如果你想通过一个完整案例把 Vue3、Pinia、Vue Router、Axios 拦截器、前后端分离接口对接、第三方支付接入串起来这篇文章会更适合你先读。下面按我从零搭建和排错时的实际顺序来写不会只堆组件代码。1. 先拆链路登录、下单、支付三个阶段各有各的难点1.1 三个关键关口分别要解决什么第一阶段是登录。登录本身不难难的是登录完成之后用户刷新页面、打开新页面、调用接口时身份信息仍然有效。这里要做的事情包括 Token 存储、接口请求自动携带凭证、路由访问控制、登录状态失效后的统一处理。第二阶段是下单。用户从商品列表进入详情把商品加入购物车填写收货信息和备注然后提交订单。这个阶段看起来只是表单提交真正容易出问题的是金额计算、商品快照、订单号和后续支付参数的组织。前端展示的价格是给人看的后端生成的订单金额才是真正参与计算的。第三阶段是支付。前端调用支付接口拉起收银台用户完成支付然后系统通过回调或主动查询确认订单状态。这里最容易误解的是前端不能自己把订单改成已支付支付结果必须以后端验证为准。很多学员在这个环节卡住不是代码语法有问题而是对支付流程的角色分工不清楚。1.2 什么样的人适合拿这个项目练手这个实战案例适合三类人已经写过 Vue3 基础但没完整做过一个多页面业务系统的前端学习者。准备面试简历里需要一个完整电商项目场景并能讲清楚状态管理和接口鉴权的候选人。平时只做后台管理系统想接触 C 端流程、订单、支付对接的前端开发。三类人的共同点在于需要理解“前端工程”和“业务闭环”之间的连接。1.3 验收标准先定下来开始写代码前先想清楚“什么算跑通”用户未登录时访问订单页能自动跳回登录页登录后能回到原目标页面。调用需要身份信息的接口能统一在请求头携带 Token。Token 失效时页面不会白屏会清理状态并重新登录。商品加入购物车后金额、数量、总价能正确变化。提交订单后能拿到订单号并能继续发起支付。支付成功与否页面最终展示的状态与后端一致。这些验收点没跑通之前做的功能都只能算“界面演示”。2. 工程骨架Vue3 项目依赖选型和目录划分要提前定好2.1 推荐技术组合与最低环境以当前 Vue3 生态中最常用的组合为例构建工具Vite。路由Vue Router 4。状态管理Pinia。HTTP 请求Axios。UI 组件库如果做 PC 端商城可以用 Element Plus如果做移动端可以用 Vant 4。Node.js 版本建议使用 18 或 20 的 LTS 版本Vite 5 及更高版本对 Node 版本有明确要求版本太老会直接启动失败。包管理器使用 npm 或 pnpm 都可以项目内锁定一个即可不要混用。创建项目的命令不同版本 Vite 略有差异常见写法是npm create vitelatest vue3-shop -- --template vue cd vue3-shop npm install npm install vue-router4 pinia axios如果你需要页面级路由和组件库再把组件库加进去。2.2 目录结构建议按“模块”划分而不是按“文件类型”堆在一起很多初学的项目会把所有页面放在 views 里所有请求放在一个 api.js 里短期可行后面链路一长就会乱。更推荐按业务模块组织src/ api/ auth.js goods.js cart.js order.js pay.js router/ index.js guard.js stores/ user.js cart.js order.js views/ login/ goods/ cart/ order/ pay/ utils/ request.js layout/ index.vue这样的好处是登录相关接口只在 auth.js 里维护购物车状态只在 cart store 里维护订单接口只在 order.js 里维护。修改某个模块不影响其他页面。2.3 接口返回结构先统一后面联调才省事前后端分离项目最怕每个接口返回结构都不一样。建议和后端约定统一格式{ code: 0, message: ok, data: {} }code 为 0 表示业务成功非 0 为业务失败。HTTP 状态码可以正常使用 200 表示请求已经到达后端并被处理401 表示未登录或 Token 失效。如果把所有业务错误都塞到 HTTP 状态码里前端处理会非常痛苦。开发阶段还需要配置跨域代理。Vite 的 vite.config.js 里可以通过 server.proxy 把以 /api 开头的请求转发到后端地址这样浏览器不会直接跨域也能更好地模拟线上同域部署。3. 登录流程关键不是登录按钮而是令牌的生命周期3.1 登录页要做的三件事以账号密码登录为例点击登录按钮后需要顺序完成三件事校验表单。调用登录接口换取 Token。保存 Token拉取当前用户信息进入目标页面。表单校验可以用组件库自带的规则也可以用计算属性做按钮的禁用态。这里很自然能用到computed当账号、密码都满足长度要求时按钮才可点击否则保持禁用。const form reactive({ username: , password: }) const canSubmit computed(() { return form.username.trim().length 0 form.password.length 6 })登录成功后的数据保存我建议放在 Pinia 的 user store 里统一管理再配合 localStorage 做持久化。不要把 Token 散落存在多个页面里。页面刷新后需要从持久化存储恢复状态这部分逻辑也集中在 user store 中处理。3.2 Axios 拦截器解决的是“每次请求都带 Token”这件事如果每个接口请求都手动写Authorization代码会非常难维护。正确做法是在 Axios 实例的请求拦截器里统一处理service.interceptors.request.use((config) { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config })响应拦截器统一处理后端返回。如果后端返回 401说明登录失效这时应该清理用户状态并跳转登录页。这里要注意两点一是不管项目里有多少个页面在发请求这个逻辑只写一遍二是跳转登录页时要带上当前路由地址登录成功后可以回跳。路由守卫负责控制页面访问权限。不需要登录就能看的一般只有登录页、商品列表和商品详情。订单、支付、个人中心都需要登录。在 Vue Router 的全局前置守卫里做判断router.beforeEach((to) { const token localStorage.getItem(token) if (!token to.meta.requiresAuth) { return { name: login, query: { redirect: to.fullPath } } } return true })这里最容易出现的问题是死循环已登录用户访问登录页又写了“已登录跳首页”的逻辑就可能一直在两个路由之间横跳。比较稳妥的做法是只处理“未登录访问受限页面”这一种情况登录页的访问策略单独判断。3.3 “登录失败”常见原因不是密码错误而是环境不对我在合作项目里看到最多的登录失败原因按出现频率排序是接口地址没走代理直接请求了一个不存在或不允许跨域的后端地址。后端要求的请求头是Content-Type: application/json但前端用表单格式提交。账号密码字段名不一致比如后端要求mobile前端传的是username。Token 保存后没有在后续请求中带上后端认为未登录。开发环境用了错误的登录接口环境比如本机没有启动后端服务却连接了线上测试环境。排查顺序也很固定先看浏览器 Network 面板里请求有没有发出去再看状态码和返回内容再对比后端接口文档最后看控制台有没有跨域或代理错误。不要一上来就怀疑 Vue 代码写错了。如果项目还涉及验证码前端还需要在发起登录前先获取验证码图片并把返回的 captchaKey 一并传到后端。现在很多项目也会用图形滑块验证逻辑类似先拿到验证通过后的凭证再随账号密码一起提交。4. 商品到购物车再到订单状态统一是关键4.1 购物车状态放在集中式 store不要每个页面存一份购物车涉及页面不止一个商品详情页加入购物车购物车页面修改数量底部导航栏显示角标下单页需要读取选中的商品。如果每个页面都自己维护一份数据同步一定会出问题。用 Pinia 管理购物车核心是几个 action加入购物车。修改数量。删除选中项。清空已下单项。计算选中商品总金额。总金额用 store 里的 getter 或组件里的 computed 来派生不手工维护一个变量否则操作数量后容易忘记更新。购物车接口如果是登录后才能使用加入购物车的请求要在请求头带上 Token后端以用户维度存储。如果是未登录也可以加购就需要本地持久化购物车数据登录后再做合并。两种模式在很多商城同时存在项目里要明确采用哪一种。4.2 下单前要处理的不仅是表单还有金额和库存快照现在电商实战项目中订单提交页通常会展示收货地址。商品清单。商品单价、数量、总价。运费、优惠券、实付款。前端要把这些数据展示清楚但真正提交给后端的参数一般只需要地址 ID、商品 ID 与数量以及可选的备注。后端会在自己的订单服务里重新计算金额而不是直接信任前端传来的总价。这是前后端职责边界问题前端可以不传总价或者传了总价只是给后端校验。前端真正要确认的是订单提交后能拿到订单 ID并且跳转到支付或订单详情页时能把订单 ID 传过去。下单过程中有两个容易忽略的细节。一个是重复提交用户连续点击“提交订单”按钮可能生成多笔订单。需要在提交中状态加锁按钮 loading接口完成后恢复。另一个是商品快照下单后商品价格或售货状态变化不应该影响已生成的订单这部分虽然主要由后端实现但前端要清楚订单展示的数据是下单时的快照。4.3 Vue3 里 computed 和 watch 在这个阶段怎么用这里单独说一下computed和watch的使用场景因为支付环节和订单金额联调时这两个 API 用错会导致页面数据不更新或频繁触发请求。computed适合做派生数据总价、总数、按钮禁用态、优惠金额。这些数据由其他响应式数据计算而来不应该单独定义一个变量去手动改。手动赋值最容易出现“数据改了页面没变”。watch适合做有副作用的操作订单状态变化后触发跳转、支付结果变化后轮询订单状态、购物车数量变化后更新本地存储。这类操作需要监听某个值的变化然后执行一个动作。下单确认页经常有这样的需求用户切换收货地址时运费跟着变化。这里运费其实是根据地址数据、商品重量等计算出来的用 computed 更合适而不是在 watch 里写一堆 set 逻辑。除非切换地址后还需要额外请求运费接口那才需要用 watch 来触发接口。5. 支付集成前端只负责“发起”不能负责“确认”5.1 起步阶段优先用沙箱环境个人学习 Vue3 电商项目时很难直接拿到真实商户号因此支付这一步常见做法是接支付宝沙箱环境。支付宝开放平台提供的沙箱环境不需要真实营业执照开发者可以拿到一组测试账号和测试商家信息在沙箱里发起支付并收到回调通知。这个过程和真实环境基本一致只是资金是虚拟的。对接步骤大致是在支付宝开放平台控制台开通沙箱应用。配置 RSA2 公钥和私钥。拿到应用的 AppID、支付宝公钥、应用私钥。后端调用支付宝 SDK 创建订单返回一段表单或二维码参数。前端拿到支付参数唤醒收银台。微信支付的沙箱或测试商户申请比支付宝要严格一些。如果还没有商户号可以先按支付宝沙箱把整套流程跑通理解了支付回调机制再迁移到微信支付或聚合支付整体思路是一致的。5.2 前端调用支付接口的代码结构前端不要自己拼签名字符串这是后端职责。合理流程是前端请求后端“创建支付单”接口后端在服务端调用支付平台接口返回前端需要的支付参数。前端拿到参数按平台要求调用对应 SDK 或跳转方法。支付结果页面展示。以支付宝网页支付返回的表单参数为例后端可能返回一段自动提交的 HTML 或一个跳转链接前端处理方式不同。如果是二维码场景后端可能返回 QRCode 图片内容和订单号前端轮询订单状态。项目里可以封装一个支付 API 模块统一处理三种场景// 伪代码具体接口以后端为准 async function createPayment(orderId) { const res await payApi.create(orderId) // res.data 里可能是 payUrl、qrCodeContent 或 form 表单 return res.data }如果是移动端 H5支付宝或微信各自的唤起方式不一样。支付宝通常用AlipayJSBridge或返回页面跳转微信支付则依赖微信内置浏览器、JSAPI 或扫码支付。初学者第一次做很容易卡在“为什么 PC 上点支付没有反应”原因往往是当前运行环境与支付类型不匹配。5.3 支付失败、支付超时和“支付中”怎么处理新手最容易犯的错误是调用支付接口返回成功后立刻把订单状态改成“已支付”。这是不安全的因为用户可能中途取消支付平台可能尚未确认成功。正确做法是支付接口返回成功只代表“收银台已拉起”。真正的支付成功依赖两种方式确认后端异步回调或前端主动查询。前端可以轮询订单状态但不能仅凭一次轮询结果就永久确定最终状态。这里要设计一个合理的“支付中”状态。常见处理是弹出支付结果等待页或者支付完成后由后端回调修改订单状态前端在回到订单页时重新查询订单。热词里那条requestpayment:fail banned的错误经常出现在小程序或部分移动端环境中。它不一定是前端代码问题通常和支付权限、虚拟商品类目、当前小程序账号没有开通支付能力有关。测试时要确认使用的是已开通对应能力的商户号而且支付的购买对象符合平台规则。遇到这类错误时先到支付平台后台查看能力配置和类目权限不要只在前端反复改代码。如果用户完成了支付但前端没有收到回调通知也不要直接把页面状态改成“支付失败”。正确流程是提供“我已完成支付”的按钮点击后主动查询后端订单状态让后端确认。6. 后端回调与订单状态一致性前端项目也要懂这层边界6.1 支付回调决定最终订单状态在前后端分离项目中支付回调通常不经过前端页面而是支付平台直接请求后端配置的通知地址。这意味着即使前端页面关闭整个支付闭环仍然可以由后端和支付平台完成。前端能做的是在流程上配合向用户展示“订单支付中”。定时查询订单接口获取实时状态。当订单状态变为已支付或已关闭时停止轮询。如果项目里的后端也是自己写的要保证回调接口是稳定且不依赖登录态的。支付平台回调后端时不可能携带前端 Token因此回调接口属于开放接口只能靠支付平台签名验证来源。6.2 查询和回调的幂等性支付回调可能会因为网络原因被支付平台重复发送。后端不能收到一次回调就把订单状态直接覆盖必须先判断当前订单状态是否已经是“已支付”。如果已经是最终状态直接返回成功响应即可不再重复处理库存和流水。前端轮询和回调可能是并发的。用户支付成功后支付平台回调后端同时前端正在发查询请求。两条链路同时走到后端必须保证最终订单状态一致。建议订单状态至少分为状态含义前端展示CREATED已创建等待支付待支付PAID已支付待发货CLOSED已关闭已关闭REFUNDING退款中退款中REFUNDED已退款已退款前端的订单状态展示应该以后端返回的字段为准不要自己根据页面步骤推断。6.3 如果项目不接真实支付也要留好接口边界没有对接真实支付条件时可以在项目里实现一个“模拟支付”模块点击支付按钮后通过一个专用的模拟支付接口把订单标记为已支付。但代码结构上仍然保留真实支付方案的接口位等有商户号之后替换成真实支付服务。不要用 setTimeout 三秒后直接改订单状态那种写法会让整套流程失去实际价值面试时也很难解释清楚。7. 联调阶段的高频问题与排查清单7.1 按现象先去定位而不是盲目重构登录、下单、支付三个链路串起来联调时大部分问题集中在这几个现象里。第一个现象是登录成功但跳转回目标页面后又变成未登录。优先检查 Pinia store 是否在页面刷新时丢失数据再看 localStorage 中 Token 有没有在跳转前被清掉。还要检查路由守卫的逻辑是不是在某个中间动作里把用户信息拉取失败当成未登录处理了。第二个现象是接口能请求成功但订单列表为空。优先确认下单请求时是否携带了正确的用户身份再确认后端写入订单时使用的用户 ID 是否来自 Token。第三个现象是支付成功后订单状态长时间不变。优先确认支付平台的回调地址能不能被外部访问后端有没有输出回调日志回调里有没有校验签名失败后直接返回错误。第四个现象是重复下单。用户在提交订单时双击按钮或者请求超时后手动刷新。前端要加按钮 loading 状态后端也需要做幂等控制前端至少要做到“同一时间只允许一次提交”。7.2 我会优先打印的日志和参数联调支付时我会在下面这些位置加日志便于定位问题提交订单前打印订单号、金额、选中的购物车 ID。发起支付前打印支付接口请求参数和后端返回的支付参数类型。轮询订单状态时打印当前订单状态和剩余轮询次数。处理支付回调时后端打印回调内容、签名校验结果和订单 ID。如果一个按钮点了没有反应先从 Network 面板看请求是否发出。没有请求是前端问题有的请求但报错看后端错误日志。联调时把环境坑先排除掉接口地址是否区分开发、测试、生产后端服务是否已启动HTTPS 页面是否在请求 HTTP 接口支付平台是否要求域名白名单。这些都是支付独有的坑前后端分离项目跑通页面不等于跑通支付。8. 从实战练习走向真实上线还需要补齐的几点8.1 安全与配置不能省支付相关流程最需要重视的是金额、签名和密钥。私钥、商户号不能写在前端代码里也不能提交到 Git 仓库。环境变量文件需要区分开发环境和生产环境并且把生产环境密钥放在后端环境变量中。前端项目在部署时要用 HTTPS避免支付参数在传输过程中被查看或篡改。登录时的密码传输也要用 HTTPS如果后端有条件可以进一步使用加密或规范的安全方案。购物车和订单数量越大的场景越要关注接口超时和重复提交问题这些都是真实项目常见的安全边界。8.2 体验细节决定项目像不像真实电商平台从功能完整走向体验完整一般还要补充登录页loading 状态。商品列表分页和骨架屏。购物车全选与金额联动。订单详情页的支付倒计时。支付结果的防重复跳转。页面离开前的状态提示。如果使用 Vue Router订单详情页、支付结果页之间可能需要传订单 ID。不要通过组件 props 传递关键业务参数应放在路由 query 参数中保证刷新页面后仍然可以读取。还要考虑路由懒加载。Vue3 项目中可以用动态导入方式加载页面组件让首屏只加载当前需要的页面。订单、支付这类低频页面更适合懒加载。8.3 面试和复盘时要能讲清楚你做了什么决策面试官最常问的不是代码函数怎么写而是项目里这些判断为什么使用 Pinia 而不是 VuexToken 存储在哪路由守卫如何避免死循环支付成功如何确认如何防止重复下单金额校验在前端还是后端。这些问题在实战项目里都能找到具体答案。真正做过完整登录到支付链路的开发不会只说“页面写好了”而是会顺着链路讲每一个决策点。如果只是学习默认配置和模拟支付通常够用如果要放到简历里或真实上线就要把日志、输出目录、回调地址、密钥管理和任务队列提前设计好。我见过不少项目功能齐全最后卡在支付回调地址内外网不通上这种问题看起来像代码复杂实际只是配置埋了雷。回到开头那句话Vue3 电商项目最值得认真跑通的就是登录到支付这条链路。它一旦跑通你在状态管理、接口鉴权、前后端协作和第三方平台对接上的能力会比单独写一百个组件页面更扎实。整个练习中如果只能保留一个目标我会选让订单状态在后端确认之后永远能正确展示到用户面前。