新闻详情

新闻详情

首页 / 资讯中心 / 详情

uni-app微信小程序登录与支付全链路实战指南

发布时间:2026/9/14 9:05:10来源:尧图网络
uni-app微信小程序登录与支付全链路实战指南
简介这是一套基于uni-app框架开发的多端商城源码面向前端开发者与小程序初学者解决跨平台电商应用快速搭建难题尤其适用于需集成微信登录与支付功能的轻量级小程序项目。资源共2000个文件以292个.vue页面组件、322个.js逻辑脚本、226个.json配置及214个.wxml214个.wxss微信小程序专属文件为主完整覆盖页面结构、交互逻辑、样式渲染与平台适配另含176个Java后端接口示例及MyBatis相关映射文件体现前后端协同设计思路。压缩包仅2.84MB结构清晰按“脚本/源码/相关文件”三级目录组织便于快速定位核心模块。目前已有668人学习下载购买者可直接运行调试、二次开发定制掌握uni-app多端编译、微信开放能力接入、小程序支付闭环等关键实践技能。1. 一个能真正在微信里跑通登录支付的 uni-app 商城不是 demo是上线前最后一关很多开发者卡在「uni-app 商城能跑但微信登录点不动、支付一直提示requestPayment:fail invalid sign」——这不是代码写错了而是没理清微信生态里三套身份体系的边界小程序用户 openid、unionid、商户号与 appid 的绑定关系、以及支付签名所需的prepay_id生命周期。这个标题里的「含小程序微信登陆、小程序微信支付」本质是要求你把 uni-app 的跨端能力精准锚定到微信官方 SDK 的调用链路上从wx.login()换取 code到后端用该 code 向微信接口换 openid再到创建订单时传入openid生成预支付交易最后前端调起wx.requestPayment()完成唤起。它适合已经用 HBuilderX 搭出商品列表和购物车、正准备对接真实微信环境的中阶开发者新手容易在appid填错环境开发版/体验版/正式版、mch_id未开通 JSAPI 支付权限、或后端返回的timeStamp类型为字符串而非数字这三处直接卡死。2. 微信登录从 wx.login() 到后端换取 openid 的完整链路与参数校验2.1 为什么 uni-app 的 uni.login() 不适用于微信小程序登录uni-app 提供的uni.login()是跨平台抽象层但在微信小程序环境下它默认调用的是wx.login()看似等价实则埋下隐患uni.login()返回的code在部分 HBuilderX 版本中会因平台判断逻辑问题返回空值或过期 code更关键的是它无法控制scope权限粒度而微信要求获取用户信息必须显式声明scope.userInfo且需用户主动授权。真实生产环境必须弃用uni.login()改用原生wx.login()wx.getUserInfo()组合调用确保 code 有效、用户态明确、后续可追溯。// ✅ 正确做法在 onLaunch 或需要登录的页面中 export default { methods: { async handleWechatLogin() { try { // 第一步获取临时登录凭证 code const loginRes await wx.login(); if (loginRes.errMsg ! login:ok) { throw new Error(wx.login 失败 loginRes.errMsg); } // 第二步调用自己后端接口传 code 换取 openid const res await uni.request({ url: https://your-api.com/api/wechat/login, method: POST, data: { code: loginRes.code } }); if (res[1].data.code 200) { uni.setStorageSync(userToken, res[1].data.token); uni.setStorageSync(openid, res[1].data.openid); } else { uni.showToast({ title: 登录失败, icon: none }); } } catch (e) { console.error(微信登录异常, e); uni.showToast({ title: 网络错误请重试, icon: none }); } } } }注意wx.login()获取的code有效期仅 5 分钟且同一 code 只能使用一次。后端必须在收到 code 后立即向微信接口https://api.weixin.qq.com/sns/jscode2session发起请求携带appid、secret、js_code和grant_typeauthorization_code四个参数。若后端缓存了旧 code 或重复使用将返回errcode: 40029。2.2 后端换取 openid 的关键参数与微信接口响应解析微信jscode2session接口返回 JSON 格式数据核心字段为openid用户在当前小程序的唯一标识和unionid同一微信开放平台下多应用共用的用户 ID。商城类应用必须依赖openid而非unionid因为微信支付 JSAPI 接口要求下单时必须传入openid且该openid必须与调起支付的小程序appid绑定一致。字段名类型是否必填说明appidstring✅小程序的 AppID不是公众号或开放平台的 AppIDsecretstring✅小程序后台「开发管理 → 开发者秘钥」中获取切勿前端暴露js_codestring✅前端wx.login()返回的 codegrant_typestring✅固定值authorization_code后端 Node.js 示例Express// POST /api/wechat/login app.post(/api/wechat/login, async (req, res) { const { code } req.body; const appId wx1234567890abcdef; // 替换为你的小程序 AppID const appSecret your_app_secret_here; // 从微信后台复制严禁硬编码在前端 try { const wechatRes await axios.get( https://api.weixin.qq.com/sns/jscode2session, { params: { appid: appId, secret: appSecret, js_code: code, grant_type: authorization_code } } ); const { openid, unionid, errcode, errmsg } wechatRes.data; if (errcode) { return res.status(400).json({ code: 400, msg: 微信接口错误${errmsg} }); } // ✅ 关键此处必须保存 openid并关联到用户 session 或 token const token jwt.sign({ openid }, process.env.JWT_SECRET, { expiresIn: 7d }); res.json({ code: 200, msg: 登录成功, token, openid, unionid: unionid || null // unionid 仅当小程序绑定开放平台时存在 }); } catch (e) { res.status(500).json({ code: 500, msg: 服务器内部错误 }); } });提示若返回errcode: 40013说明appid与secret不匹配检查是否填错小程序 AppID不是公众号、或secret是否被重置过若返回errcode: 40001则是secret错误或已过期。3. 微信支付从创建预支付订单到前端调起 requestPayment 的全流程落地3.1 微信支付 JSAPI 接口调用前提三证合一与权限开通在代码层面能调通wx.requestPayment()之前必须完成三项微信侧配置缺一不可商户号mch_id已通过微信支付商户平台认证且开通「JSAPI 支付」能力小程序 AppID 已在商户平台「产品中心 → APPID 授权管理」中绑定该商户号后端服务器 IP 已添加至商户平台「账户中心 → API 安全 → IP 白名单」否则调用微信统一下单接口会返回invalid ip。注意很多开发者忽略第二项——即使你有商户号、有小程序 AppID若未在商户平台手动绑定二者后端调用unifiedorder接口时会返回errcode: 10005appid not bind mchid此时前端wx.requestPayment()会直接报requestPayment:fail invalid sign但错误日志里完全不提绑定问题极易误判为签名错误。3.2 后端统一下单接口unifiedorder的核心参数与签名逻辑微信支付 JSAPI 下单必须调用https://api.mch.weixin.qq.com/pay/unifiedorder这是一个 HTTPS POST 接口必须使用证书apiclient_cert.pem apiclient_key.pem进行双向认证且所有参数需按微信规则生成sign签名。关键字段如下表参数名类型是否必填说明appidstring✅小程序 AppIDmch_idstring✅商户号nonce_strstring✅随机字符串32位以内建议用时间戳随机数bodystring✅商品描述如uni-app商城-订单#10001out_trade_nostring✅商户系统内部订单号必须全局唯一建议用时间戳6位随机数total_feeint✅订单金额单位为分如 100 元 →10000spbill_create_ipstring✅调用统一下单的机器 IP不能填 localhost 或 127.0.0.1notify_urlstring✅支付结果异步通知地址必须为 HTTPS且能被微信外网访问trade_typestring✅固定值JSAPIopenidstring✅用户在该小程序下的 openid必须与 appid 匹配Node.js 使用wechat-pay库示例简化版const WechatPay require(wechat-pay).default; const pay new WechatPay({ appid: wx1234567890abcdef, mch_id: 1234567890, partner_key: your_mch_key_here, // 商户平台「API安全 → 密钥」设置的32位KEY pfx: fs.readFileSync(./cert/apiclient_cert.pem), // 证书路径 passphrase: your_mch_key_here // 与 partner_key 相同 }); // 创建预支付订单 app.post(/api/pay/create, async (req, res) { const { openid, orderNo, amount } req.body; // amount 单位分 try { const result await pay.unifiedOrder({ body: uni-app商城-订单${orderNo}, out_trade_no: orderNo, total_fee: amount, spbill_create_ip: 119.123.45.67, // 服务器公网IP非本地IP notify_url: https://your-domain.com/api/pay/notify, trade_type: JSAPI, openid }); // ✅ 微信返回的 prepay_id 是调起支付的关键 const { prepay_id, timestamp, nonceStr, package: pkg, signType, paySign } result; // 构造前端调用 wx.requestPayment 所需参数 res.json({ code: 200, data: { appId: wx1234567890abcdef, timeStamp: String(Date.now()), // 注意必须是字符串类型微信要求 nonceStr, package: prepay_id${prepay_id}, signType: MD5, paySign } }); } catch (e) { console.error(统一下单失败, e.response?.data || e.message); res.status(500).json({ code: 500, msg: 支付创建失败 }); } });关键细节timeStamp字段在微信文档中要求为「当前时间戳单位秒」但实际wx.requestPayment()接口校验时接受毫秒级时间戳字符串如1712345678901若传入整数类型会报invalid time stamppackage字段必须严格为prepay_idxxx格式前后不能有空格。3.3 前端调起支付wx.requestPayment 的最小可行调用与错误捕获uni-app 中调用wx.requestPayment()必须使用uni.getProvider()显式指定平台避免 HBuilderX 自动降级到支付宝或其它支付方式// ✅ 在支付确认页的 methods 中 async doPayment(orderNo) { try { // 1. 先请求后端获取支付参数 const res await uni.request({ url: https://your-api.com/api/pay/create, method: POST, data: { openid: uni.getStorageSync(openid), orderNo, amount: this.orderAmount * 100 // 转为分 } }); const payParams res[1].data.data; // 2. 调起微信支付 await wx.requestPayment({ ...payParams, success: (res) { console.log(支付成功, res); uni.showToast({ title: 支付成功, icon: success }); setTimeout(() { uni.navigateTo({ url: /pages/order/success?orderNo orderNo }); }, 1500); }, fail: (err) { console.error(支付失败, err); // ❗重点微信支付失败 err.errMsg 可能为以下几种 // requestPayment:fail cancel —— 用户取消 // requestPayment:fail system error —— 系统错误如签名失效 // requestPayment:fail invalid sign —— 签名错误最常见检查后端 sign 生成逻辑 if (err.errMsg.includes(cancel)) { uni.showToast({ title: 已取消支付, icon: none }); } else { uni.showToast({ title: 支付失败请重试, icon: none }); } } }); } catch (e) { console.error(支付流程异常, e); uni.showToast({ title: 网络错误请重试, icon: none }); } }提示若fail回调中err.errMsg为invalid sign请立即检查后端paySign生成逻辑——是否漏加keyxxx、是否参数排序错误、是否package字段格式不对必须是prepay_idxxx、是否timeStamp传成了数字而非字符串。4. 微信支付回调与订单状态同步防止用户关闭页面导致状态丢失4.1 异步通知notify_url的幂等性设计与验签逻辑微信支付成功后会以 POST 方式向你配置的notify_url发送 XML 格式通知。该通知可能重复发送网络超时重试且无任何身份验证头必须靠微信签名sign字段验真。核心步骤解析 XML → 提取所有非空字段 → 按字典序拼接keyvalue字符串 → 末尾追加key商户KEY→ MD5 小写 → 与sign字段比对。Node.js Express 示例// POST /api/pay/notify 注意此路由不能有 bodyParser.json() 中间件需原始 body app.post(/api/pay/notify, async (req, res) { // 1. 获取原始 XML body const xml await getRawBody(req); // 2. 解析 XML使用 xml2js const parsed await parseStringPromise(xml); const { xml: data } parsed; // 3. 验签提取所有非空字段按 key 字典序排序拼接 const sign data.sign[0]; delete data.sign; const signStr Object.keys(data) .filter(key data[key][0] typeof data[key][0] string) .sort() .map(key ${key}${data[key][0]}) .join() keyyour_mch_key_here; // 注意key 是商户平台设置的 API KEY const mySign md5(signStr).toLowerCase(); if (mySign ! sign.toLowerCase()) { return res.send(xmlreturn_code![CDATA[FAIL]]/return_codereturn_msg![CDATA[SIGN ERROR]]/return_msg/xml); } // 4. ✅ 验签通过处理业务逻辑 if (data.result_code[0] SUCCESS data.return_code[0] SUCCESS) { const outTradeNo data.out_trade_no[0]; const transactionId data.transaction_id[0]; // 更新订单状态为「已支付」并记录 transaction_id await updateOrderStatus(outTradeNo, paid, transactionId); // 发货、扣库存、发短信等后续操作... } // 5. 必须返回 SUCCESS XML否则微信会持续重发 res.send(xmlreturn_code![CDATA[SUCCESS]]/return_codereturn_msg![CDATA[OK]]/return_msg/xml); });注意getRawBody需使用raw-body库获取原始流不能依赖body-parserupdateOrderStatus必须是原子操作如数据库UPDATE ... WHERE status unpaid防止重复通知导致状态被多次更新。4.2 主动查询补救机制当 notify_url 不可达时的兜底方案若服务器宕机、防火墙拦截或域名 DNS 故障导致notify_url无法接收微信通知订单将长期处于「待支付」状态。此时需启用「订单支付状态主动查询」作为兜底在用户点击「去支付」后启动一个setInterval每 3 秒调用后端/api/pay/query?out_trade_noxxx接口后端调用微信https://api.mch.weixin.qq.com/pay/orderquery接口传入out_trade_no查询订单状态一旦查到trade_stateSUCCESS立即更新本地订单状态并清除定时器若连续查询 10 次即 30 秒仍未成功提示用户「支付结果未知请在「我的订单」中查看」。uni-app 前端主动轮询示例startPolling(orderNo) { this.pollingTimer setInterval(async () { try { const res await uni.request({ url: https://your-api.com/api/pay/query?out_trade_no${orderNo} }); const { trade_state } res[1].data; if (trade_state SUCCESS) { clearInterval(this.pollingTimer); uni.showToast({ title: 支付成功, icon: success }); uni.navigateTo({ url: /pages/order/success?orderNo orderNo }); } else if (trade_state CLOSED || trade_state REVOKED) { clearInterval(this.pollingTimer); uni.showToast({ title: 支付已关闭, icon: none }); } } catch (e) { console.warn(查询支付状态失败继续轮询); } }, 3000); }关键点轮询必须设上限如 10 次避免无限请求查询接口返回trade_state字段含义需严格对照微信文档SUCCESS支付成功、REFUND转入退款、NOTPAY未支付、CLOSED已关闭、REVOKED已撤销、USERPAYING用户支付中。5. 实战排错5 类高频报错的定位路径与修复指令5.1requestPayment:fail invalid sign—— 签名错误的三层排查法这是微信支付最常遇到的报错表面是签名错实则可能源于三个层级层级检查点验证命令/方法前端层timeStamp是否为字符串package是否为prepay_idxxx格式signType是否为MD5console.log(typeof payParams.timeStamp, payParams.package)后端层paySign生成时是否漏掉keyxxx参数是否包含空值字段nonceStr是否与下单时一致在unifiedOrder返回后打印result.sign与本地计算的mySign对比微信侧商户号是否开通 JSAPI 支付小程序 AppID 是否已在商户平台绑定商户平台「API安全」中 KEY 是否与代码一致登录 pay.weixin.qq.com 进入「产品中心 → 开发配置」逐项核对快速验证指令在后端unifiedOrder成功返回后立即用 Postman 模拟wx.requestPayment参数调用https://api.mch.weixin.qq.com/pay/orderquery查询该out_trade_no若能查到订单则证明签名逻辑正确问题一定出在前端传参或微信侧配置。5.2login:fail scope is not authorized—— 用户拒绝授权后的优雅降级当用户首次进入小程序点击登录按钮却弹出「拒绝授权」提示wx.getUserInfo()会直接失败。此时不能简单报错而应引导用户手动开启// 在 wx.getUserInfo 失败回调中 fail: (err) { if (err.errMsg.includes(scope not authorized)) { // ✅ 弹出引导框说明需要授权才能使用完整功能 uni.showModal({ title: 授权提示, content: 为了提供完整的购物体验需要获取您的公开信息昵称、头像。请前往「设置」→「隐私」→「小程序授权管理」中开启。, showCancel: true, confirmText: 去设置, success: (res) { if (res.confirm) { // 跳转小程序设置页 wx.openSetting({ success: (settingRes) { if (settingRes.authSetting[scope.userInfo]) { // 用户已开启重新尝试获取 this.handleWechatLogin(); } } }); } } }); } }5.3Error: Request failed with status code 400—— 后端统一下单 400 错误的字段级定位微信unifiedorder接口返回 400 时响应体是 XML 格式需解析err_code和err_code_des字段。常见组合及修复err_codeerr_code_des修复动作INVALID_REQUESTparameter format error检查total_fee是否为整数、spbill_create_ip是否为合法公网 IP、out_trade_no是否含特殊字符ORDERPAIDorder already paidout_trade_no重复提交确保订单号全局唯一建议Date.now() Math.random().toString(36).substr(2, 6)NOAUTHno permission商户号未开通 JSAPI 支付或小程序 AppID 未在商户平台绑定调试技巧在后端unifiedOrder调用前打印所有参数对象用 JSON.stringify 格式化输出人工比对微信文档字段要求特别注意total_fee必须是整数body不能含 emoji 或控制字符。5.4wx.requestPayment:fail system error—— 真机调试必备的证书与域名白名单检查此错误只在真机出现模拟器无法复现。原因几乎全是环境配置问题小程序后台「开发管理 → 开发者工具」中是否开启了「不校验合法域名」仅开发阶段可用上线必须关闭requestPayment所需的appId、timeStamp、nonceStr、package、signType、paySign六个字段是否全部由后端返回且前端未做任何修改尤其注意package字段前端拼接会导致签名失效HBuilderX 运行时是否勾选了「微信开发者工具」而非「浏览器」浏览器环境无法调起微信支付。5.5 支付成功但 notify_url 未触发 —— 网络连通性四步诊断当用户看到「支付成功」弹窗但订单状态仍为「待支付」大概率是notify_url未收到微信回调检查域名是否备案且 HTTPS 有效使用 SSL Labs 测试证书链完整性检查服务器防火墙执行curl -v https://your-domain.com/api/pay/notify看是否返回 404 或连接超时检查微信商户平台「API安全 → IP白名单」是否已添加服务器公网 IP不是内网 IP检查 Nginx/Apache 日志是否有POST /api/pay/notify的 4xx/5xx 记录确认请求是否到达 Web 服务器。终极验证在notify_url路由开头加入fs.writeFileSync(/tmp/wechat_notify.log, JSON.stringify(req.body), utf8)部署后让同事扫码支付立即查看/tmp/wechat_notify.log是否有内容写入——这是判断请求是否抵达服务端的黄金标准。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Tolaria 的 Git 提交与推送实战指南:手动管理、AutoGit 自动检查点与安全提交实践 2026/9/14 10:17:26

Tolaria 的 Git 提交与推送实战指南:手动管理、AutoGit 自动检查点与安全提交实践

Tolaria 的 Git 提交与推送实战指南:手动管理、AutoGit 自动检查点与安全提交实践 【免费下载链接】tolaria Desktop app to manage markdown knowledge bases 项目地址: https://gitcode.com/GitHub_Trending/to/tolaria Tolaria 可以作为 Git 启用型 vault…

阅读更多 →
函数调用能力评测实战:用 BFCL(Berkeley Function Calling Leaderboard)全面评估 Qwen3-Coder 模型 2026/9/14 10:17:26

函数调用能力评测实战:用 BFCL(Berkeley Function Calling Leaderboard)全面评估 Qwen3-Coder 模型

函数调用能力评测实战:用 BFCL(Berkeley Function Calling Leaderboard)全面评估 Qwen3-Coder 模型 【免费下载链接】Qwen3-Coder Qwen3-Coder is the code version of Qwen3, the large language model series developed by Qwen team. 项…

阅读更多 →
Wasp 中间件配置指南:全局、API 级与路径级 Middleware 定制 2026/9/14 10:17:26

Wasp 中间件配置指南:全局、API 级与路径级 Middleware 定制

Wasp 中间件配置指南:全局、API 级与路径级 Middleware 定制 【免费下载链接】wasp The batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full…

阅读更多 →
军工卫星视频传输:WebUploader改造与安全优化实践 2026/9/14 10:17:26

军工卫星视频传输:WebUploader改造与安全优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
JuiceFS FUSE 挂载选项完全指南:从 `-o` 参数到 /etc/fstab 的精细调优 2026/9/14 10:17:26

JuiceFS FUSE 挂载选项完全指南:从 `-o` 参数到 /etc/fstab 的精细调优

JuiceFS FUSE 挂载选项完全指南:从 -o 参数到 /etc/fstab 的精细调优 【免费下载链接】juicefs JuiceFS is a distributed POSIX file system built on top of Redis and S3. 项目地址: https://gitcode.com/GitHub_Trending/ju/juicefs JuiceFS 提供了多种访…

阅读更多 →
OpenClaw Codex Happy Path 提示词快照:如何逐层复现 Codex 运行时的模型绑定 Prompt 栈 2026/9/14 10:14:26

OpenClaw Codex Happy Path 提示词快照:如何逐层复现 Codex 运行时的模型绑定 Prompt 栈

OpenClaw Codex Happy Path 提示词快照:如何逐层复现 Codex 运行时的模型绑定 Prompt 栈 【免费下载链接】openclaw The AI that really does things. Any OS. Any Platform. The lobster way. 🦞 项目地址: https://gitcode.com/GitHub_Trending/cl/…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞