刚接手店铺,顾客问能不能扫码支付,我却连菜鸟小程序的支付入口在哪都找不到!
以为小程序扫码支付是个很高深的技术活,尤其对于刚接触小程序开发的“菜鸟”来说,看到文档里那些AppID、商户号、回调URL,头都大了。其实你只要把逻辑拆开看,就跟你去便利店买东西扫码付款一样简单——你扫别人,或者别人扫你。小程序里的扫码支付,本质上就是这两种场景的数字化。
咱们先解决第一个问题:你的小程序,到底想让用户“扫什么”?
大多数菜鸟朋友容易犯一个错误,一上来就研究“怎么调起微信支付”,结果发现代码写完了,但用户根本找不到扫码入口。真正有价值的第一步,是确定你的支付场景。举个例子,你在本地开了一家水果店,想让顾客在小程序里下单后扫码付款。这时候你需要的是“用户扫你的码”,也就是商户码。而如果你做了一个共享充电宝小程序,用户需要“扫设备上的码”来租借,那就是另一种逻辑。
咱们直接说实操。假设你是最普遍的情况:用户在小程序里选好商品,生成订单,然后调起支付。这一步,微信官方其实给了很清晰的“小程序支付”接口,但坑在于很多教程只告诉你调wx.requestPayment,却不告诉你前置条件。
前置条件有三个,缺一个都调不起来:第一,你的小程序必须关联一个微信商户号,并且商户号要开通JSAPI支付权限。第二,你的后端服务器要能生成一个“预支付交易单”,拿到一个叫prepay_id的东西。第三,前端的签名算法必须对,卡在签名上,因为官方文档给的示例代码有时候会误导新手。
我建议你用一个更稳的办法:直接用微信官方提供的“支付工具包”,别自己手写签名。在微信商户平台里,有一个“API安全”模块,里面可以下载官方SDK。比如你用PHP,直接下载官方PHP版的SDK,里面已经把签名、数组排序、生成随机字符串这些麻烦事封装好了。你只需要传几个参数:订单号、金额、商品描述、用户openid。注意这个openid必须是小程序端通过wx.login获取到的,不能随便填。
拿到prepay_id之后,前端调用wx.requestPayment,传入timeStamp、nonceStr、package(就是"prepay_id=xxx")、signType(MD5或HMAC-SHA256)、paySign。这里有个独门技巧:很多菜鸟发现明明参数都对了,但就是报错“支付验证签名失败”。大概率是因为你传的nonceStr和后台生成签名的那个随机字符串不一致。解决办法很简单,后台生成签名时用的nonceStr,原封不动传给前端,别重新生成。
再来说第二种场景:用户扫你的码。这个常见于线下门店,比如你贴一个二维码在收银台,顾客扫了之后直接进入商品页面或者支付页面。这里的关键不是支付代码,而是“二维码怎么生成”。直接去网上找在线二维码生成器,但那种码扫出来是一个网址,用户还得手动点击按钮才能支付,体验很割裂。
正确的做法是:用微信的“小程序码”接口。在微信公众平台里,有一个“生成小程序码”的功能,你可以生成一个带参数的码。比如参数里带上门店ID、桌号、或者商品ID,用户扫进去之后,小程序直接拿到参数,自动带出对应的订单页,用户点击支付即可。这个流程非常顺滑,而且参数是加密的,比普通二维码安全。你只需要在后台调用微信的getUnlimitedQRCode接口,传入scene参数(比如scene=store_001),然后小程序端在App.js的onLaunch里通过options.query.scene拿到这个参数,再跳转到对应页面。
这里有一个本地化的案例:我帮一个做社区团购的朋友改造过支付流程。他原来让用户在群里发红包,然后手动登记,经常对不上账。后来我帮他做了个小程序码,贴在每个小区门口。用户扫码进去,直接看到自己所在小区的今日团购清单,选好商品后,支付页面自动带出“自提点”和“团长ID”。因为码里带了scene参数,后台能识别是哪个小区的用户,这样团长对账时直接看后台数据就行,再也不会漏单。这个方案比单纯做支付更有价值,因为它解决了“对账难”这个实际痛点。
还有第三种场景:你的小程序需要“扫别人”来支付。比如你是做共享设备的,用户扫描设备上的二维码,然后支付使用。这个场景下,用户打开小程序的“扫一扫”功能,扫设备码,然后调起支付。这里有个容易踩的坑:微信的扫一扫接口wx.scanCode,扫出来的结果是一个字符串,你需要把这个字符串发到后台,后台根据这个字符串找到对应的设备或订单信息,再生成预支付单。
很多菜鸟会在这里犯一个逻辑错误:以为扫完码就直接弹出支付。实际上,扫完码之后你还需要展示一个确认页面,让用户看到“你要租借的设备是XX,费用是XX元”,用户点击确认再支付。为什么?因为用户可能扫错了码,或者设备已被占用。我见过一个做自助洗车机的开发者,他直接让用户扫完码就支付,结果用户扫了设备A的码,但设备A正在被使用,钱却扣了,导致大量投诉。后来改成先展示设备状态,用户确认后再支付,退款率直接降了70%。
对比一下这三种场景,你会发现最核心的东西其实是同一个:拿到用户的openid,生成预支付单,调起支付。但不同场景下的前置步骤差别很大。如果你只是做一个简单的电商小程序,那么场景一就够了;如果你是实体店,场景二能帮你把线下流量引到线上;如果你是做物联网或共享服务,场景三必不可少。
最后补充一个容易被忽略的细节:支付成功后的回调处理。以为用户付完钱就万事大吉了,结果发现订单状态没更新,用户跑来问“我钱扣了怎么还没发货”。这是因为支付成功后的回调有两种方式:一种是前端通过wx.requestPayment的success回调来更新状态,但这种方式不可靠,因为用户可能支付成功后网络断了,或者用户手动关闭了页面。更稳妥的做法是依赖微信服务器端的“支付结果通知”,也就是你在商户平台配置的那个回调URL。微信服务器会主动向你的后台发一个POST请求,告诉你这笔订单支付成功。你的后台收到这个通知后,再更新订单状态,同时给用户发模板消息通知。
这个回调URL一定要做好签名验证,别直接信任传过来的数据。我见过有人因为没做验证,被恶意用户伪造支付成功通知,白嫖了几百单。验证方法很简单:微信支付官方SDK里自带了一个验证函数,你只需要把收到的xml数据传进去,它会自动验证签名和金额是否匹配。
如果你把上面这些点都吃透了,那么不管你是开小店的、做社区服务的、还是搞共享经济的,都能用小程序扫码支付把生意跑通。而且你会发现,真正让客户愿意付款的,往往不是支付代码写得有多漂亮,而是你的支付流程有多顺畅、多安全、多符合本地用户的习惯。

